Utils/Logger: Remove dependency on libboost_datetime
g0dil [Fri, 16 May 2008 22:22:44 +0000 (22:22 +0000)]
Console: ConfigFile support

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@845 270642c3-0616-0410-b53a-bc976706d245

15 files changed:
Utils/Logger/AreaRegistry.cc
Utils/Logger/AreaRegistry.ih
Utils/Logger/IOStreamTarget.cc
Utils/Logger/IOStreamTarget.hh
Utils/Logger/Log.test.cc
Utils/Logger/Target.cc
Utils/Logger/Target.cci
Utils/Logger/Target.cti
Utils/Logger/Target.hh
Utils/Logger/Target.ih
Utils/Logger/TimeSource.cc [new file with mode: 0644]
Utils/Logger/TimeSource.cci [new file with mode: 0644]
Utils/Logger/TimeSource.cti [new file with mode: 0644]
Utils/Logger/TimeSource.hh [new file with mode: 0644]
Utils/Logger/TimeSource.ih [new file with mode: 0644]

index ed38550..c0cbf14 100644 (file)
@@ -84,7 +84,7 @@ prefix_ void senf::log::detail::AreaBase::removeRoutingCache(Target & target,
     routingCache_[stream.index].limit = l;
 }
 
-prefix_ void senf::log::detail::AreaBase::write(boost::posix_time::ptime timestamp,
+prefix_ void senf::log::detail::AreaBase::write(time_type timestamp,
                                                 StreamBase const & stream, unsigned level,
                                                 std::string msg)
     const
index 41ca82b..a3b6124 100644 (file)
@@ -30,8 +30,8 @@
 #include <string>
 #include <vector>
 #include <list>
-#include <boost/date_time/posix_time/posix_time.hpp>
 #include "Levels.hh"
+#include "TimeSource.hh"
 
 ///////////////////////////////ih.p////////////////////////////////////////
 
@@ -57,7 +57,7 @@ namespace detail {
         unsigned limit(StreamBase const & stream) const;
         void updateRoutingCache(Target & target, StreamBase const & stream, unsigned limit) const; 
         void removeRoutingCache(Target & target, StreamBase const & stream) const; 
-        void write(boost::posix_time::ptime timestamp, StreamBase const & stream, unsigned level,
+        void write(time_type timestamp, StreamBase const & stream, unsigned level,
               std::string msg) const;
 
     private:
index 0d798bb..487e508 100644 (file)
@@ -30,6 +30,7 @@
 #include <locale>
 #include <boost/algorithm/string/trim.hpp>
 #include <boost/tokenizer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 //#include "IOStreamTarget.mpp"
 #define prefix_
@@ -53,7 +54,7 @@ prefix_ senf::log::IOStreamTarget::IOStreamTarget(std::ostream & os)
 ////////////////////////////////////////
 // private members
 
-prefix_ void senf::log::IOStreamTarget::v_write(boost::posix_time::ptime timestamp,
+prefix_ void senf::log::IOStreamTarget::v_write(time_type timestamp,
                                                 std::string const & stream,
                                                 std::string const & area, unsigned level,
                                                 std::string const & message)
index 2a2763a..05f9eee 100644 (file)
@@ -73,7 +73,7 @@ namespace log {
         ///////////////////////////////////////////////////////////////////////////
 
     protected:
-        void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
+        void v_write(time_type timestamp, std::string const & stream, 
                      std::string const & area, unsigned level, 
                      std::string const & message);
 
index 5936544..0fbbfb9 100644 (file)
@@ -55,10 +55,12 @@ BOOST_AUTO_UNIT_TEST(logger)
     target.clear();
     
     SENF_LOG((senf::log::IMPORTANT)("Important message"));
+    std::cerr << target.str();
     BOOST_CHECK( ! target.str().empty() );
     target.clear();
 
     SENF_LOG((senf::log::test::LogCritical) ("Another log message: " << 10));
+    std::cerr << target.str();
     BOOST_CHECK( ! target.str().empty() );
     target.clear();
 
@@ -66,10 +68,12 @@ BOOST_AUTO_UNIT_TEST(logger)
         log << "Last message";
         log << " continued here";
     }));
+    std::cerr << target.str();
     BOOST_CHECK( ! target.str().empty() );
     target.clear();
 
     senf::log::test::Foo::log();
+    std::cerr << target.str();
     BOOST_CHECK( ! target.str().empty() );
     target.clear();
 
index 91d231e..d352836 100644 (file)
@@ -184,7 +184,7 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st
         area->updateRoutingCache(*this, *stream, limit);
 }
 
-prefix_ void senf::log::Target::write(boost::posix_time::ptime timestamp,
+prefix_ void senf::log::Target::write(time_type timestamp,
                                       detail::StreamBase const & stream,
                                       detail::AreaBase const & area, unsigned level,
                                       std::string const & message)
@@ -211,25 +211,10 @@ prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
     if (fallbackRouting_) {
         if (level >= stream.defaultRuntimeLimit())
             static_cast<Target &>(ConsoleTarget::instance()).v_write( 
-                (*timeSource_)(), stream.v_name(), area.v_name(), level, msg );
+                TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
     }
     else
-        area.write( (*timeSource_)(), stream, level, msg );
-}
-
-///////////////////////////////////////////////////////////////////////////
-// senf::log::TimeSource
-
-prefix_ senf::log::TimeSource::~TimeSource()
-{}
-
-///////////////////////////////////////////////////////////////////////////
-// senf::log::SystemTimeSource
-
-prefix_ boost::posix_time::ptime senf::log::SystemTimeSource::operator()()
-    const
-{
-    return boost::posix_time::microsec_clock::universal_time();
+        area.write( TimeSource::now(), stream, level, msg );
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 608d7e1..ba36a95 100644 (file)
@@ -26,6 +26,7 @@
 #include "Target.ih"
 
 // Custom includes
+#include "AreaRegistry.hh"
 
 #define prefix_ inline
 ///////////////////////////////cci.p///////////////////////////////////////
@@ -94,11 +95,6 @@ prefix_ senf::log::Target::action_t senf::log::Target::RoutingEntry::action()
 ///////////////////////////////////////////////////////////////////////////
 // senf::log::detail::TargetRegistry
 
-prefix_ void senf::log::detail::TargetRegistry::timeSource(std::auto_ptr<TimeSource> source)
-{
-    timeSource_.reset(source.release());
-}
-
 prefix_ void senf::log::detail::TargetRegistry::routed()
 {
     fallbackRouting_ = false;
@@ -113,7 +109,7 @@ prefix_ bool senf::log::detail::TargetRegistry::fallbackRouting()
 // private members
 
 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
-    : timeSource_(new SystemTimeSource()), fallbackRouting_(true)
+    : fallbackRouting_(true)
 {}
 
 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target)
@@ -126,14 +122,6 @@ prefix_ void senf::log::detail::TargetRegistry::unregisterTarget(Target * target
     targets_.erase(target);
 }
 
-///////////////////////////////////////////////////////////////////////////
-// namespace senf::log members
-
-prefix_ void senf::log::timeSource(std::auto_ptr<TimeSource> source)
-{
-    detail::TargetRegistry::instance().timeSource(source);
-}
-
 /////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
index 1608c9f..bad63ab 100644 (file)
@@ -93,12 +93,6 @@ prefix_ void senf::log::detail::write(std::string msg)
     TargetRegistry::instance().write(Stream::instance(), Area::instance(), Level::value, msg);
 }
 
-template <class Source>
-prefix_ void senf::log::timeSource()
-{
-    timeSource(std::auto_ptr<Source>(new Source()));
-}
-
 ///////////////////////////////cti.e///////////////////////////////////////
 #undef prefix_
 
index 664f5b2..ff8fc54 100644 (file)
 
 // Custom includes
 #include <set>
-#include <boost/date_time/posix_time/posix_time.hpp>
+#include <vector>
 #include <boost/utility.hpp>
 #include <boost/type_traits/is_convertible.hpp>
 #include "../singleton.hh"
 #include "../mpl.hh"
 #include "StreamRegistry.hh"
-#include "AreaRegistry.hh"
 #include "../Exception.hh"
+#include "TimeSource.hh"
 
 //#include "Target.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -54,6 +54,7 @@ namespace senf {
 namespace log {
     
     namespace detail { class TargetRegistry; }
+    namespace detail { class AreaBase; }
 
     /** \brief Logging target base class
         
@@ -331,14 +332,14 @@ namespace log {
 
         void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
 
-        void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
+        void write(time_type timestamp, detail::StreamBase const & stream,
                    detail::AreaBase const & area, unsigned level, std::string const & message);
 
 #   ifdef DOXYGEN
     protected:
 #   endif
 
-        virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
+        virtual void v_write(time_type timestamp, std::string const & stream, 
                              std::string const & area, unsigned level, 
                              std::string const & message) = 0;
                                         ///< Called to write out the routing message
@@ -369,55 +370,6 @@ namespace log {
         friend class detail::TargetRegistry;
     };
 
-    /** \brief Log message time source abstract base class
-
-        Instances derived from TimeSource provide the Logging library with the current date/time
-        value. The \c operator() member must be implemented to return the current universal time
-        (UTC).
-
-        A new TimeSource may be installed using \ref senf::log::timeSource().
-
-        \ingroup config
-     */
-    struct TimeSource
-    {
-        virtual ~TimeSource();
-        virtual boost::posix_time::ptime operator()() const = 0;
-    };
-
-    /** \brief Default %log message time source
-
-        This time source is installed by default and uses gettimeofday() (via the Boost.DateTime
-        library) to get the current universal time.
-        
-        \ingroup config
-     */
-    struct SystemTimeSource : public TimeSource
-    {
-        virtual boost::posix_time::ptime operator()() const;
-    };
-
-    /** \brief Change %log message time source
-
-        Set the %log message time source to \a source. The logging library will take ownership of \e
-        source and will take care to free it, if necessary.
-
-        Since the time source class will in almost all cases be default constructible, see the
-        template overload for a simpler interface.
-
-        \ingroup config
-     */
-    void timeSource(std::auto_ptr<TimeSource> source);
-
-    /** \brief Change %log message time source
-
-        Set the %log message time source to (an instance of) \a Source.  \a Source must be default
-        constructible, otherwise use the non-template senf::log::timeSource() overload.
-
-        \ingroup config
-     */
-    template <class Source> void timeSource();
-
 }}
 
 ///////////////////////////////hh.e////////////////////////////////////////
index 9ef0e0e..01d0728 100644 (file)
@@ -28,7 +28,6 @@
 
 // Custom includes
 #include <memory>
-#include <boost/scoped_ptr.hpp>
 #include <boost/type_traits/is_same.hpp>
 #include <boost/static_assert.hpp>
 
@@ -48,8 +47,6 @@ namespace detail {
         void write(StreamBase const & stream, AreaBase const & area, unsigned level, 
                    std::string msg);
 
-        void timeSource(std::auto_ptr<TimeSource> source);
-
         void routed();
         bool fallbackRouting();
 
@@ -61,7 +58,6 @@ namespace detail {
 
         typedef std::set<Target *> Targets;
         Targets targets_;
-        boost::scoped_ptr<TimeSource> timeSource_;
 
         bool fallbackRouting_;
         
diff --git a/Utils/Logger/TimeSource.cc b/Utils/Logger/TimeSource.cc
new file mode 100644 (file)
index 0000000..0cab0d9
--- /dev/null
@@ -0,0 +1,68 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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.
+
+/** \file
+    \brief TimeSource non-inline non-template implementation */
+
+#include "TimeSource.hh"
+#include "TimeSource.ih"
+
+// Custom includes
+#include <time.h>
+#include "../Exception.hh"
+
+//#include "TimeSource.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::log::TimeSource
+
+prefix_ senf::log::TimeSource::~TimeSource()
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::log::SystemTimeSource
+
+prefix_ senf::log::time_type senf::log::SystemTimeSource::operator()()
+    const
+{
+    struct ::timespec tm;
+    if (::clock_gettime(CLOCK_MONOTONIC, &tm) < 0)
+        SENF_THROW_SYSTEM_EXCEPTION("::timer_gettime()");
+    return static_cast<time_type>(tm.tv_sec)*1000000000ll+tm.tv_nsec;
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "TimeSource.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Logger/TimeSource.cci b/Utils/Logger/TimeSource.cci
new file mode 100644 (file)
index 0000000..a5173f6
--- /dev/null
@@ -0,0 +1,78 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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.
+
+/** \file
+    \brief TimeSource inline non-template implementation */
+
+#include "TimeSource.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::log::TimeSource
+
+prefix_ senf::log::time_type senf::log::TimeSource::now()
+{
+    return detail::TimeSourceManager::instance().now();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::log::detail::TimeSourceManager
+
+prefix_ senf::log::detail::TimeSourceManager::TimeSourceManager()
+    : timeSource_ (new SystemTimeSource())
+{}
+
+prefix_ senf::log::time_type senf::log::detail::TimeSourceManager::now()
+{
+    return (*timeSource_)();
+}
+
+prefix_ void senf::log::detail::TimeSourceManager::timeSource(std::auto_ptr<TimeSource> source)
+{
+    timeSource_.reset(source.release());
+}
+
+///////////////////////////////////////////////////////////////////////////
+// namespace senf::log members
+
+prefix_ void senf::log::timeSource(std::auto_ptr<TimeSource> source)
+{
+    detail::TimeSourceManager::instance().timeSource(source);
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Logger/TimeSource.cti b/Utils/Logger/TimeSource.cti
new file mode 100644 (file)
index 0000000..659b65a
--- /dev/null
@@ -0,0 +1,54 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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.
+
+/** \file
+    \brief TimeSource inline template implementation */
+
+#include "TimeSource.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// namespace senf::log members
+
+template <class Source>
+prefix_ void senf::log::timeSource()
+{
+    timeSource(std::auto_ptr<Source>(new Source()));
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Logger/TimeSource.hh b/Utils/Logger/TimeSource.hh
new file mode 100644 (file)
index 0000000..f88bb3b
--- /dev/null
@@ -0,0 +1,109 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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.
+
+/** \file
+    \brief TimeSource public header */
+
+#ifndef HH_TimeSource_
+#define HH_TimeSource_ 1
+
+// Custom includes
+#include <boost/cstdint.hpp>
+#include <memory>
+
+//#include "TimeSource.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace log {
+
+    typedef boost::int_fast64_t time_type;
+
+    /** \brief Log message time source abstract base class
+
+        Instances derived from TimeSource provide the Logging library with the current date/time
+        value. The \c operator() member must be implemented to return the current universal time
+        (UTC).
+
+        A new TimeSource may be installed using \ref senf::log::timeSource().
+
+        \ingroup config
+     */
+    struct TimeSource
+    {
+        virtual ~TimeSource();
+        virtual time_type operator()() const = 0;
+
+        static time_type now();
+    };
+
+    /** \brief Default %log message time source
+
+        This time source is installed by default and uses gettimeofday() (via the Boost.DateTime
+        library) to get the current universal time.
+        
+        \ingroup config
+     */
+    struct SystemTimeSource : public TimeSource
+    {
+        virtual time_type operator()() const;
+    };
+
+    /** \brief Change %log message time source
+
+        Set the %log message time source to \a source. The logging library will take ownership of \e
+        source and will take care to free it, if necessary.
+
+        Since the time source class will in almost all cases be default constructible, see the
+        template overload for a simpler interface.
+
+        \ingroup config
+     */
+    void timeSource(std::auto_ptr<TimeSource> source);
+
+    /** \brief Change %log message time source
+
+        Set the %log message time source to (an instance of) \a Source.  \a Source must be default
+        constructible, otherwise use the non-template senf::log::timeSource() overload.
+
+        \ingroup config
+     */
+    template <class Source> void timeSource();
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "TimeSource.cci"
+//#include "TimeSource.ct"
+#include "TimeSource.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Logger/TimeSource.ih b/Utils/Logger/TimeSource.ih
new file mode 100644 (file)
index 0000000..c0ab54f
--- /dev/null
@@ -0,0 +1,69 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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.
+
+/** \file
+    \brief TimeSource internal header */
+
+#ifndef IH_TimeSource_
+#define IH_TimeSource_ 1
+
+// Custom includes
+#include <boost/scoped_ptr.hpp>
+#include "../singleton.hh"
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace log {
+namespace detail {
+
+    class TimeSourceManager
+        : public senf::singleton<TimeSourceManager>
+    {
+    public:
+        TimeSourceManager();
+
+        using senf::singleton<TimeSourceManager>::instance;
+
+        time_type now();
+        void timeSource(std::auto_ptr<TimeSource> source);
+        
+    private:
+        
+        boost::scoped_ptr<TimeSource> timeSource_;
+    };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End: