<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade 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.

Abaclade 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 Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_RANGE_HXX
#define _ABACLADE_RANGE_HXX

#ifndef _ABACLADE_HXX
   #error "Please #include <abaclade.hxx> before this file"
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::range

namespace abc {

/*! Represents an iterable interval of values defined by a beginning and an end, inclusive and
exclusive respectively. */
template <typename T>
class range : public support_explicit_operator_bool<range<T>> {
public:
   //! Iterator for range values.
   class iterator : public std::iterator<std::bidirectional_iterator_tag, T> {
   public:
      /*! Constructor.

      @param t
         Current value.
      */
      explicit iterator(T t) :
         m_t(std::move(t)) {
      }

      /*! Dereferencing operator.

      @return
         Reference to the current node.
      */
      T operator*() const {
         return m_t;
      }

      /*! Dereferencing member access operator.

      @return
         Pointer to the current value.
      */
      T * operator->() {
         return &m_t;
      }
      T const * operator->() const {
         return &m_t;
      }

      /*! Preincrement operator.

      @return
         *this after it’s moved to the value following the one currently referenced.
      */
      iterator & operator++() {
         ++m_t;
         return *this;
      }

      /*! Postincrement operator.

      @return
         Iterator to the value following the one referenced by this iterator.
      */
      iterator operator++(int) {
         return iterator(m_t++);
      }

      /*! Predecrement operator.

      @return
         *this after it’s moved to the value preceding the one currently referenced.
      */
      iterator & operator--() {
         --m_t;
         return *this;
      }

      /*! Postdecrement operator.

      @return
         Iterator to the value preceding the one referenced by this iterator.
      */
      iterator operator--(int) {
         return iterator(m_t--);
      }

      /*! Equality relational operator.

      @param it
         Object to compare to *this.
      @return
         true if *this has the same value as it, or false otherwise.
      */
      bool operator==(iterator const & it) const {
         return m_t == it.m_t;
      }

      /*! Inequality relational operator.

      @param it
         Object to compare to *this.
      @return
         true if *this has a different value than it, or false otherwise.
      */
      bool operator!=(iterator const & it) const {
         return !operator==(it);
      }

      /*! Returns the underlying value.

      @return
         Reference to the current value.
      */
      T & base() {
         return m_t;
      }
      T const & base() const {
         return m_t;
      }

   private:
      //! Current value.
      T m_t;
   };

   typedef std::reverse_iterator<iterator> reverse_iterator;

public:
   /*! Constructor.

   @param tBegin
      First value in the range.
   @param tEnd
      Value beyond the last one in the range.
   */
   range() :
      m_tBegin(),
      m_tEnd() {
   }
   range(T tBegin, T tEnd) :
      m_tBegin(std::move(tBegin)),
      m_tEnd(std::move(tEnd)) {
   }

   /*! Boolean evaluation operator.

   @return
      true if the range is non-empty, or false if it’s empty.
   */
   explicit_operator_bool() const {
      return m_tBegin != m_tEnd;
   }

   /*! Equality relational operator.

   @param r
      Object to compare to *this.
   @return
      true if *this has the same begin and end as r, or false otherwise.
   */
   bool operator==(range const & r) const {
      return m_tBegin == r.m_tBegin && m_tEnd == r.m_tEnd;
   }

   /*! Inequality relational operator.

   @param r
      Object to compare to *this.
   @return
      true if *this has a different begin and/or end than r, or false otherwise.
   */
   bool operator!=(range const & r) const {
      return !operator==(r);
   }

   /*! Returns an iterator to the start of the range.

   @return
      Iterator to the first value in the range.
   */
   iterator begin() const {
      return iterator(m_tBegin);
   }

   /*! Returns true if the specified value is included in the range.

   @param t
      Value to check for inclusion.
   @return
      true if t is included in [begin(), end()), or false otherwise.
   */
   bool contains(T const & t) const {
      return t >= m_tBegin && t < m_tEnd;
   }

   /*! Returns an iterator to the end of the range.

   @return
      Value beyond the last in the range.
   */
   iterator end() const {
      return iterator(m_tEnd);
   }

   /*! Returns the count of values included in the range.

   @return
      Count of values.
   */
   std::size_t size() const {
      return m_tBegin < m_tEnd ? static_cast<std::size_t>(m_tEnd - m_tBegin) : 0;
   }

private:
   //! First value in the range.
   T m_tBegin;
   //! Value beyond the last one in the range.
   T m_tEnd;
};

/*! Creates an abc::range by inferring the range type from its arguments.

@param tBegin
   First value in the range.
@param tEnd
   Value beyond the last one in the range.
@return
   Range covering [begin, end).
*/
template <typename T>
range<T> make_range(T tBegin, T tEnd) {
   return range<T>(std::move(tBegin), std::move(tEnd));
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef _ABACLADE_RANGE_HXX
<commit_msg>Add shift operator support to abc::range<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade 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.

Abaclade 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 Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_RANGE_HXX
#define _ABACLADE_RANGE_HXX

#ifndef _ABACLADE_HXX
   #error "Please #include <abaclade.hxx> before this file"
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::range

namespace abc {

/*! Represents an iterable interval of values defined by a beginning and an end, inclusive and
exclusive respectively. */
template <typename T>
class range : public support_explicit_operator_bool<range<T>> {
public:
   //! Iterator for range values.
   class iterator : public std::iterator<std::bidirectional_iterator_tag, T> {
   public:
      /*! Constructor.

      @param t
         Current value.
      */
      explicit iterator(T t) :
         m_t(std::move(t)) {
      }

      /*! Dereferencing operator.

      @return
         Reference to the current node.
      */
      T operator*() const {
         return m_t;
      }

      /*! Dereferencing member access operator.

      @return
         Pointer to the current value.
      */
      T * operator->() {
         return &m_t;
      }
      T const * operator->() const {
         return &m_t;
      }

      /*! Preincrement operator.

      @return
         *this after it’s moved to the value following the one currently referenced.
      */
      iterator & operator++() {
         ++m_t;
         return *this;
      }

      /*! Postincrement operator.

      @return
         Iterator to the value following the one referenced by this iterator.
      */
      iterator operator++(int) {
         return iterator(m_t++);
      }

      /*! Predecrement operator.

      @return
         *this after it’s moved to the value preceding the one currently referenced.
      */
      iterator & operator--() {
         --m_t;
         return *this;
      }

      /*! Postdecrement operator.

      @return
         Iterator to the value preceding the one referenced by this iterator.
      */
      iterator operator--(int) {
         return iterator(m_t--);
      }

      /*! Equality relational operator.

      @param it
         Object to compare to *this.
      @return
         true if *this has the same value as it, or false otherwise.
      */
      bool operator==(iterator const & it) const {
         return m_t == it.m_t;
      }

      /*! Inequality relational operator.

      @param it
         Object to compare to *this.
      @return
         true if *this has a different value than it, or false otherwise.
      */
      bool operator!=(iterator const & it) const {
         return !operator==(it);
      }

      /*! Returns the underlying value.

      @return
         Reference to the current value.
      */
      T & base() {
         return m_t;
      }
      T const & base() const {
         return m_t;
      }

   private:
      //! Current value.
      T m_t;
   };

   typedef std::reverse_iterator<iterator> reverse_iterator;

public:
   /*! Constructor.

   @param tBegin
      First value in the range.
   @param tEnd
      Value beyond the last one in the range.
   */
   range() :
      m_tBegin(),
      m_tEnd() {
   }
   range(T tBegin, T tEnd) :
      m_tBegin(std::move(tBegin)),
      m_tEnd(std::move(tEnd)) {
   }

   /*! Boolean evaluation operator.

   @return
      true if the range is non-empty, or false if it’s empty.
   */
   explicit_operator_bool() const {
      return m_tBegin != m_tEnd;
   }

   /*! Right-shift-assignment operator.

   @param t
      Amount by which to shift/translate the range towards positive infinity.
   @return
      *this after its begin() and end() have been increased by t.
   */
   range & operator>>=(T const & t) {
      m_tBegin += t;
      m_tEnd += t;
      return *this;
   }

   /*! Left-shift-assignment operator.

   @param t
      Amount by which to shift/translate the range towards negative infinity.
   @return
      *this after its begin() and end() have been decreased by t.
   */
   range & operator<<=(T const & t) {
      m_tBegin -= t;
      m_tEnd -= t;
      return *this;
   }

   /*! Right-shift operator.

   @param t
      Amount by which to shift/translate the range towards positive infinity.
   @return
      Range covering *this with begin() and end() increased by t.
   */
   range operator>>(T const & t) const {
      return range(*this) >>= t;
   }

   /*! Left-shift operator.

   @param t
      Amount by which to shift/translate the range towards negative infinity.
   @return
      Range covering *this with begin() and end() decreased by t.
   */
   range operator<<(T const & t) const {
      return range(*this) <<= t;
   }

   /*! Equality relational operator.

   @param r
      Object to compare to *this.
   @return
      true if *this has the same begin and end as r, or false otherwise.
   */
   bool operator==(range const & r) const {
      return m_tBegin == r.m_tBegin && m_tEnd == r.m_tEnd;
   }

   /*! Inequality relational operator.

   @param r
      Object to compare to *this.
   @return
      true if *this has a different begin and/or end than r, or false otherwise.
   */
   bool operator!=(range const & r) const {
      return !operator==(r);
   }

   /*! Returns an iterator to the start of the range.

   @return
      Iterator to the first value in the range.
   */
   iterator begin() const {
      return iterator(m_tBegin);
   }

   /*! Returns true if the specified value is included in the range.

   @param t
      Value to check for inclusion.
   @return
      true if t is included in [begin(), end()), or false otherwise.
   */
   bool contains(T const & t) const {
      return t >= m_tBegin && t < m_tEnd;
   }

   /*! Returns an iterator to the end of the range.

   @return
      Value beyond the last in the range.
   */
   iterator end() const {
      return iterator(m_tEnd);
   }

   /*! Returns the count of values included in the range.

   @return
      Count of values.
   */
   std::size_t size() const {
      return m_tBegin < m_tEnd ? static_cast<std::size_t>(m_tEnd - m_tBegin) : 0;
   }

private:
   //! First value in the range.
   T m_tBegin;
   //! Value beyond the last one in the range.
   T m_tEnd;
};

/*! Creates an abc::range by inferring the range type from its arguments.

@param tBegin
   First value in the range.
@param tEnd
   Value beyond the last one in the range.
@return
   Range covering [begin, end).
*/
template <typename T>
range<T> make_range(T tBegin, T tEnd) {
   return range<T>(std::move(tBegin), std::move(tEnd));
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef _ABACLADE_RANGE_HXX
<|endoftext|>


<commit_before>/*
*  Author(s):
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*  - Chris  Kilner <ckilner@aldebaran-robotics.com>
*
*  Copyright (C) 2010 Aldebaran Robotics
*/

#include <qi/messaging/src/subscriber_impl.hpp>
#include <qi/transport/transport_subscriber.hpp>
#include <qi/messaging/src/network/master_endpoint.hpp>
#include <qi/serialization/message.hpp>
#include <qi/log.hpp>

namespace qi {
  namespace detail {

    SubscriberImpl::SubscriberImpl(const std::string& name, Context *ctx)
      : MasterClient(name, ctx),
        _transportSubscriber(new qi::transport::TransportSubscriber(Context::transportContext(ctx)))
    {
      _endpointContext.type = SUBSCRIBER_ENDPOINT;
      init();
      registerMachine(_machineContext);
      registerEndpoint(_endpointContext);
      _transportSubscriber->setSubscribeHandler(this);
    }

    SubscriberImpl::~SubscriberImpl() {
      unregisterEndpoint(_endpointContext);
    }

    void SubscriberImpl::subscribe(const std::string& signature, qi::Functor* f) {
      std::string endpoint = locateTopic(signature, _endpointContext);
      if (endpoint.empty()) {
        qisWarning << "Subscriber \"" << _endpointContext.name << "\": Topic not found \"" << signature << "\"" << std::endl;
         return;
      }

      qisDebug << "SubscriberImpl::subscribe: storing callback for : " << signature << std::endl;
      ServiceInfo si(signature, f);
      _subscriberCallBacks.insert(signature, si);

      if (! _subscribedEndpoints.exists(endpoint)) {
        xConnect(endpoint);
        if (_subscribedEndpoints.empty()) {
          // hmm creates the thread
          // TODO move the thread out of the transport subscriber
          _transportSubscriber->subscribe();
        }
        _subscribedEndpoints.insert(endpoint, endpoint);
      }
    }

    void SubscriberImpl::unsubscribe(const std::string& signature) {
      _subscriberCallBacks.remove(signature);
      // TODO cleanup the transport subscriber if no longer needed
      // TODO tell the master that we have unsubscribed
    }

    void SubscriberImpl::subscribeHandler(qi::transport::Buffer &requestMessage) {
      qisDebug << "SubscriberImpl::subscribeHandler called " << std::endl;
      qi::serialization::Message ser(requestMessage);
      std::string targetTopic;
      ser.readString(targetTopic);
      const ServiceInfo& si = _subscriberCallBacks.get(targetTopic);
      if (si.methodName.empty() || si.functor == NULL) {
        qisDebug << "SubscriberImpl::subscribeHandler: handler not found for \"" << targetTopic << "\"" << std::endl;
      } else {
        qisDebug << "SubscriberImpl::subscribeHandler: found handler for \"" << targetTopic << "\"" << std::endl;
        qi::serialization::Message sd;
        si.functor->call(ser, sd);
      }
    }

    bool SubscriberImpl::xConnect(const std::string& address) {
      try {
        qisDebug << "SubscriberImpl::xConnect: connecting to: " << address << std::endl;
        _transportSubscriber->connect(address);
        _isInitialized = true;
      } catch(const std::exception& e) {
        _isInitialized = false;
        qisDebug << "Subscriber failed to create subscriber for address \"" << address << "\" Reason: " << e.what() << std::endl;
      }
      return _isInitialized;
    }

  }
}
<commit_msg>Less subscriber debug output<commit_after>/*
*  Author(s):
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*  - Chris  Kilner <ckilner@aldebaran-robotics.com>
*
*  Copyright (C) 2010 Aldebaran Robotics
*/

#include <qi/messaging/src/subscriber_impl.hpp>
#include <qi/transport/transport_subscriber.hpp>
#include <qi/messaging/src/network/master_endpoint.hpp>
#include <qi/serialization/message.hpp>
#include <qi/log.hpp>

namespace qi {
  namespace detail {

    SubscriberImpl::SubscriberImpl(const std::string& name, Context *ctx)
      : MasterClient(name, ctx),
        _transportSubscriber(new qi::transport::TransportSubscriber(Context::transportContext(ctx)))
    {
      _endpointContext.type = SUBSCRIBER_ENDPOINT;
      init();
      registerMachine(_machineContext);
      registerEndpoint(_endpointContext);
      _transportSubscriber->setSubscribeHandler(this);
    }

    SubscriberImpl::~SubscriberImpl() {
      unregisterEndpoint(_endpointContext);
    }

    void SubscriberImpl::subscribe(const std::string& signature, qi::Functor* f) {
      std::string endpoint = locateTopic(signature, _endpointContext);
      if (endpoint.empty()) {
        qisWarning << "Subscriber \"" << _endpointContext.name << "\": Topic not found \"" << signature << "\"" << std::endl;
         return;
      }

      qisDebug << "SubscriberImpl::subscribe: storing callback for : " << signature << std::endl;
      ServiceInfo si(signature, f);
      _subscriberCallBacks.insert(signature, si);

      if (! _subscribedEndpoints.exists(endpoint)) {
        xConnect(endpoint);
        if (_subscribedEndpoints.empty()) {
          // hmm creates the thread
          // TODO move the thread out of the transport subscriber
          _transportSubscriber->subscribe();
        }
        _subscribedEndpoints.insert(endpoint, endpoint);
      }
    }

    void SubscriberImpl::unsubscribe(const std::string& signature) {
      _subscriberCallBacks.remove(signature);
      // TODO cleanup the transport subscriber if no longer needed
      // TODO tell the master that we have unsubscribed
    }

    void SubscriberImpl::subscribeHandler(qi::transport::Buffer &requestMessage) {
      qi::serialization::Message ser(requestMessage);
      std::string targetTopic;
      ser.readString(targetTopic);
      const ServiceInfo& si = _subscriberCallBacks.get(targetTopic);
      if (si.methodName.empty() || si.functor == NULL) {
        qisDebug << "SubscriberImpl::subscribeHandler: handler not found for \"" << targetTopic << "\"" << std::endl;
      } else {
        //qisDebug << "SubscriberImpl::subscribeHandler: found handler for \"" << targetTopic << "\"" << std::endl;
        qi::serialization::Message sd;
        si.functor->call(ser, sd);
      }
    }

    bool SubscriberImpl::xConnect(const std::string& address) {
      try {
        qisDebug << "SubscriberImpl::xConnect: connecting to: " << address << std::endl;
        _transportSubscriber->connect(address);
        _isInitialized = true;
      } catch(const std::exception& e) {
        _isInitialized = false;
        qisDebug << "Subscriber failed to create subscriber for address \"" << address << "\" Reason: " << e.what() << std::endl;
      }
      return _isInitialized;
    }

  }
}
<|endoftext|>


<commit_before>#include <ctime>
#include <iostream>
#include <cassert>

#include "policy/kasp.pb.h"
#include "enforcer/enforcerdata.h"
#include "enforcer/enforcer.h"

// Interface of this cpp file is used by C code, we need to declare
// extern "C" to prevent linking errors.
extern "C" {
#include "enforcer/enforce_cmd.h"
#include "enforcer/enforce_task.h"
#include "shared/duration.h"
#include "shared/file.h"
#include "daemon/engine.h"
}

static const char *enforce_cmd_str = "enforce_cmd";

/**
 * Print help for the 'enforce' command
 *
 */
void help_enforce_zones_cmd(int sockfd)
{
    char buf[ODS_SE_MAXLINE];
    (void) snprintf(buf, ODS_SE_MAXLINE,
    "enforce         enumerate all zones and run the enforcer once for every "
                    "zone.\n");
// "enforce <zone>  read zone and schedule for immediate enforcement.\n"
// "enforce --all   read all zones and schedule all for enforcement.\n"
    ods_writen(sockfd, buf, strlen(buf));
}

/**
 * Handle the 'enforce' command.
 *
 */
int handled_enforce_zones_cmd(int sockfd, engine_type* engine, const char *cmd,
                              ssize_t n)
{
    // Start a task that will go through all zones and run enforce on every one
    // of them
    char buf[ODS_SE_MAXLINE];
    ods_status status = ODS_STATUS_OK;

    if (n != 7 || strncmp(cmd, "enforce", 7) != 0) return 0;
    ods_log_debug("[%s] enforce command", enforce_cmd_str);

    /* start the enforcer task */
    /* schedule task */
    task_type *task = enforce_task(engine->config);
    if (!task) {
        ods_log_crit("[%s] failed to create enforce task",
                     enforce_cmd_str);
    } else {
        status = schedule_task_from_thread(engine->taskq, task, 0);
        if (status != ODS_STATUS_OK) {
            ods_log_crit("[%s] failed to create enforce task",
                         enforce_cmd_str);

            (void)snprintf(buf, ODS_SE_MAXLINE, "Unable to schedule enforce "
                           "task.\n");
            ods_writen(sockfd, buf, strlen(buf));
        } else  {
            (void)snprintf(buf, ODS_SE_MAXLINE, "Scheduled enforce task.\n");
            ods_writen(sockfd, buf, strlen(buf));
        }
    }

    return 1;
}
<commit_msg>Also make the enforce command by default execute an enforce directly and start a task when --task is supplied as a parameter<commit_after>#include <ctime>
#include <iostream>
#include <cassert>

#include "policy/kasp.pb.h"
#include "enforcer/enforcerdata.h"
#include "enforcer/enforcer.h"

// Interface of this cpp file is used by C code, we need to declare
// extern "C" to prevent linking errors.
extern "C" {
#include "enforcer/enforce_cmd.h"
#include "enforcer/enforce_task.h"
#include "shared/duration.h"
#include "shared/file.h"
#include "daemon/engine.h"
}

static const char *enforce_cmd_str = "enforce_cmd";

/**
 * Print help for the 'enforce' command
 *
 */
void help_enforce_zones_cmd(int sockfd)
{
    char buf[ODS_SE_MAXLINE];
    (void) snprintf(buf, ODS_SE_MAXLINE,
    "enforce         enumerate all zones and run the enforcer once for every "
                    "zone.\n");
// "enforce <zone>  read zone and schedule for immediate enforcement.\n"
// "enforce --all   read all zones and schedule all for enforcement.\n"
    ods_writen(sockfd, buf, strlen(buf));
}

/**
 * Handle the 'enforce' command.
 *
 */
int handled_enforce_zones_cmd(int sockfd, engine_type* engine, const char *cmd,
                              ssize_t n)
{
    // Start a task that will go through all zones and run enforce on every one
    // of them
    char buf[ODS_SE_MAXLINE];
    ods_status status = ODS_STATUS_OK;

    if (n < 7 || strncmp(cmd, "enforce", 7) != 0) return 0;
    ods_log_debug("[%s] enforce command", enforce_cmd_str);

    if (cmd[7] == '\0') {
        cmd = "";
    } else if (cmd[7] != ' ') {
        return 0;
    } else {
        cmd = &cmd[7+1];
    }

    if (strncmp(cmd, "--task", 7) == 0) {
        /* start the enforcer task */
        /* schedule task */
        task_type *task = enforce_task(engine->config);
        if (!task) {
            ods_log_crit("[%s] failed to create enforce task",
                         enforce_cmd_str);
        } else {
            status = schedule_task_from_thread(engine->taskq, task, 0);
            if (status != ODS_STATUS_OK) {
                ods_log_crit("[%s] failed to create enforce task",
                             enforce_cmd_str);

                (void)snprintf(buf, ODS_SE_MAXLINE, "Unable to schedule enforce "
                               "task.\n");
                ods_writen(sockfd, buf, strlen(buf));
            } else  {
                (void)snprintf(buf, ODS_SE_MAXLINE, "Scheduled enforce task.\n");
                ods_writen(sockfd, buf, strlen(buf));
            }
        }
    } else {
        perform_enforce(sockfd,engine->config);
    }

    return 1;
}
<|endoftext|>


<commit_before>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of class QGCCore
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QFile>
#include <QFlags>
#include <QThread>
#include <QSplashScreen>
#include <QPixmap>
#include <QDesktopWidget>
#include <QPainter>
#include <QStyleFactory>
#include <QAction>

#include <QDebug>

#include "configuration.h"
#include "QGC.h"
#include "QGCCore.h"
#include "MainWindow.h"
#include "GAudioOutput.h"

#ifdef OPAL_RT
#include "OpalLink.h"
#endif
#include "UDPLink.h"
#include "MAVLinkSimulationLink.h"

/**
 * @brief Constructor for the main application.
 *
 * This constructor initializes and starts the whole application. It takes standard
 * command-line parameters
 *
 * @param argc The number of command-line parameters
 * @param argv The string array of parameters
 **/

QGCCore::QGCCore(int &argc, char* argv[]) : QApplication(argc, argv)
{
    // Set application name
    this->setApplicationName(QGC_APPLICATION_NAME);
    this->setApplicationVersion(QGC_APPLICATION_VERSION);
    this->setOrganizationName(QLatin1String("OPENMAV"));
    this->setOrganizationDomain("org.qgroundcontrol");

    // Set settings format
    QSettings::setDefaultFormat(QSettings::IniFormat);

    // Check application settings
    // clear them if they mismatch
    // QGC then falls back to default
    QSettings settings;

    // Show user an upgrade message if QGC got upgraded (see code below, after splash screen)
    bool upgraded = false;
    QString lastApplicationVersion("");
    if (settings.contains("QGC_APPLICATION_VERSION"))
    {
        QString qgcVersion = settings.value("QGC_APPLICATION_VERSION").toString();
        if (qgcVersion != QGC_APPLICATION_VERSION)
        {
            lastApplicationVersion = qgcVersion;
            settings.clear();
            // Write current application version
            settings.setValue("QGC_APPLICATION_VERSION", QGC_APPLICATION_VERSION);
            upgraded = true;
        }
    }
    else
    {
        // If application version is not set, clear settings anyway
        settings.clear();
        // Write current application version
        settings.setValue("QGC_APPLICATION_VERSION", QGC_APPLICATION_VERSION);
    }

    settings.sync();

    // Show splash screen
    QPixmap splashImage(":/files/images/splash.png");
    QSplashScreen* splashScreen = new QSplashScreen(splashImage);
    // Delete splash screen after mainWindow was displayed
    splashScreen->setAttribute(Qt::WA_DeleteOnClose);
    splashScreen->show();
    processEvents();
    splashScreen->showMessage(tr("Loading application fonts"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));

    // Exit main application when last window is closed
    connect(this, SIGNAL(lastWindowClosed()), this, SLOT(quit()));

    // Load application font
    QFontDatabase fontDatabase = QFontDatabase();
    const QString fontFileName = ":/general/vera.ttf"; ///< Font file is part of the QRC file and compiled into the app
    //const QString fontFamilyName = "Bitstream Vera Sans";
    if(!QFile::exists(fontFileName)) printf("ERROR! font file: %s DOES NOT EXIST!\n", fontFileName.toStdString().c_str());
    fontDatabase.addApplicationFont(fontFileName);
    // Avoid Using setFont(). In the Qt docu you can read the following:
    //     "Warning: Do not use this function in conjunction with Qt Style Sheets."
    // setFont(fontDatabase.font(fontFamilyName, "Roman", 12));

    // Start the comm link manager
    splashScreen->showMessage(tr("Starting Communication Links"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
    startLinkManager();

    // Start the UAS Manager
    splashScreen->showMessage(tr("Starting UAS Manager"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
    startUASManager();

    // Start the user interface
    splashScreen->showMessage(tr("Starting User Interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
    // Start UI

    // Connect links
    // to make sure that all components are initialized when the
    // first messages arrive
    UDPLink* udpLink = new UDPLink(QHostAddress::Any, 14550);
    MainWindow::instance()->addLink(udpLink);
    // Listen on Multicast-Address 239.255.77.77, Port 14550
    //QHostAddress * multicast_udp = new QHostAddress("239.255.77.77");
    //UDPLink* udpLink = new UDPLink(*multicast_udp, 14550);

#ifdef OPAL_RT
    // Add OpalRT Link, but do not connect
    OpalLink* opalLink = new OpalLink();
    MainWindow::instance()->addLink(opalLink);
#endif
    MAVLinkSimulationLink* simulationLink = new MAVLinkSimulationLink(":/demo-log.txt");
    simulationLink->disconnect();

    mainWindow = MainWindow::instance(splashScreen);

    // Remove splash screen
    splashScreen->finish(mainWindow);

    if (upgraded) mainWindow->showInfoMessage(tr("Default Settings Loaded"), tr("QGroundControl has been upgraded from version %1 to version %2. Some of your user preferences have been reset to defaults for safety reasons. Please adjust them where needed.").arg(lastApplicationVersion).arg(QGC_APPLICATION_VERSION));

    // Check if link could be connected
    if (!udpLink->connect())
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not connect UDP port. Is an instance of " + qAppName() + "already running?");
        msgBox.setInformativeText("You will not be able to receive data via UDP. Please check that you're running the right executable and then re-start " + qAppName() + ". Do you want to close the application?");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        int ret = msgBox.exec();

        // Close the message box shortly after the click to prevent accidental clicks
        QTimer::singleShot(15000, &msgBox, SLOT(reject()));

        // Exit application
        if (ret == QMessageBox::Yes)
        {
            //mainWindow->close();
            QTimer::singleShot(200, mainWindow, SLOT(close()));
        }
    }

//    forever
//    {
//        QGC::SLEEP::msleep(5000);
//    }

//    mainWindow->close();
//    mainWindow->deleteLater();
//    QGC::SLEEP::msleep(200);
}

/**
 * @brief Destructor for the groundstation. It destroys all loaded instances.
 *
 **/
QGCCore::~QGCCore()
{
    //mainWindow->storeSettings();
    mainWindow->close();
    //mainWindow->deleteLater();
    // Delete singletons
	delete MainWindow::instance();
    delete LinkManager::instance();
    delete UASManager::instance();
}

/**
 * @brief Start the link managing component.
 *
 * The link manager keeps track of all communication links and provides the global
 * packet queue. It is the main communication hub
 **/
void QGCCore::startLinkManager()
{
    LinkManager::instance();
}

/**
 * @brief Start the Unmanned Air System Manager
 *
 **/
void QGCCore::startUASManager()
{
    // Load UAS plugins
    QDir pluginsDir = QDir(qApp->applicationDirPath());

#if defined(Q_OS_WIN)
    if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
        pluginsDir.cdUp();
#elif defined(Q_OS_LINUX)
    if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
        pluginsDir.cdUp();
#elif defined(Q_OS_MAC)
    if (pluginsDir.dirName() == "MacOS") {
        pluginsDir.cdUp();
        pluginsDir.cdUp();
        pluginsDir.cdUp();
    }
#endif
    pluginsDir.cd("plugins");

    UASManager::instance();

    // Load plugins

    QStringList pluginFileNames;

    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = loader.instance();
        if (plugin) {
            //populateMenus(plugin);
            pluginFileNames += fileName;
            //printf(QString("Loaded plugin from " + fileName + "\n").toStdString().c_str());
        }
    }
}

<commit_msg>Removed a bit more of old cruft<commit_after>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of class QGCCore
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QFile>
#include <QFlags>
#include <QThread>
#include <QSplashScreen>
#include <QPixmap>
#include <QDesktopWidget>
#include <QPainter>
#include <QStyleFactory>
#include <QAction>

#include <QDebug>

#include "configuration.h"
#include "QGC.h"
#include "QGCCore.h"
#include "MainWindow.h"
#include "GAudioOutput.h"

#ifdef OPAL_RT
#include "OpalLink.h"
#endif
#include "UDPLink.h"
#include "MAVLinkSimulationLink.h"

/**
 * @brief Constructor for the main application.
 *
 * This constructor initializes and starts the whole application. It takes standard
 * command-line parameters
 *
 * @param argc The number of command-line parameters
 * @param argv The string array of parameters
 **/

QGCCore::QGCCore(int &argc, char* argv[]) : QApplication(argc, argv)
{
    // Set application name
    this->setApplicationName(QGC_APPLICATION_NAME);
    this->setApplicationVersion(QGC_APPLICATION_VERSION);
    this->setOrganizationName(QLatin1String("QGroundControl"));
    this->setOrganizationDomain("org.qgroundcontrol");

    // Set settings format
    QSettings::setDefaultFormat(QSettings::IniFormat);

    // Check application settings
    // clear them if they mismatch
    // QGC then falls back to default
    QSettings settings;

    // Show user an upgrade message if QGC got upgraded (see code below, after splash screen)
    bool upgraded = false;
    QString lastApplicationVersion("");
    if (settings.contains("QGC_APPLICATION_VERSION"))
    {
        QString qgcVersion = settings.value("QGC_APPLICATION_VERSION").toString();
        if (qgcVersion != QGC_APPLICATION_VERSION)
        {
            lastApplicationVersion = qgcVersion;
            settings.clear();
            // Write current application version
            settings.setValue("QGC_APPLICATION_VERSION", QGC_APPLICATION_VERSION);
            upgraded = true;
        }
    }
    else
    {
        // If application version is not set, clear settings anyway
        settings.clear();
        // Write current application version
        settings.setValue("QGC_APPLICATION_VERSION", QGC_APPLICATION_VERSION);
    }

    settings.sync();

    // Show splash screen
    QPixmap splashImage(":/files/images/splash.png");
    QSplashScreen* splashScreen = new QSplashScreen(splashImage);
    // Delete splash screen after mainWindow was displayed
    splashScreen->setAttribute(Qt::WA_DeleteOnClose);
    splashScreen->show();
    processEvents();
    splashScreen->showMessage(tr("Loading application fonts"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));

    // Exit main application when last window is closed
    connect(this, SIGNAL(lastWindowClosed()), this, SLOT(quit()));

    // Load application font
    QFontDatabase fontDatabase = QFontDatabase();
    const QString fontFileName = ":/general/vera.ttf"; ///< Font file is part of the QRC file and compiled into the app
    //const QString fontFamilyName = "Bitstream Vera Sans";
    if(!QFile::exists(fontFileName)) printf("ERROR! font file: %s DOES NOT EXIST!\n", fontFileName.toStdString().c_str());
    fontDatabase.addApplicationFont(fontFileName);
    // Avoid Using setFont(). In the Qt docu you can read the following:
    //     "Warning: Do not use this function in conjunction with Qt Style Sheets."
    // setFont(fontDatabase.font(fontFamilyName, "Roman", 12));

    // Start the comm link manager
    splashScreen->showMessage(tr("Starting Communication Links"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
    startLinkManager();

    // Start the UAS Manager
    splashScreen->showMessage(tr("Starting UAS Manager"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
    startUASManager();

    // Start the user interface
    splashScreen->showMessage(tr("Starting User Interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
    // Start UI

    // Connect links
    // to make sure that all components are initialized when the
    // first messages arrive
    UDPLink* udpLink = new UDPLink(QHostAddress::Any, 14550);
    MainWindow::instance()->addLink(udpLink);
    // Listen on Multicast-Address 239.255.77.77, Port 14550
    //QHostAddress * multicast_udp = new QHostAddress("239.255.77.77");
    //UDPLink* udpLink = new UDPLink(*multicast_udp, 14550);

#ifdef OPAL_RT
    // Add OpalRT Link, but do not connect
    OpalLink* opalLink = new OpalLink();
    MainWindow::instance()->addLink(opalLink);
#endif
    MAVLinkSimulationLink* simulationLink = new MAVLinkSimulationLink(":/demo-log.txt");
    simulationLink->disconnect();

    mainWindow = MainWindow::instance(splashScreen);

    // Remove splash screen
    splashScreen->finish(mainWindow);

    if (upgraded) mainWindow->showInfoMessage(tr("Default Settings Loaded"), tr("QGroundControl has been upgraded from version %1 to version %2. Some of your user preferences have been reset to defaults for safety reasons. Please adjust them where needed.").arg(lastApplicationVersion).arg(QGC_APPLICATION_VERSION));

    // Check if link could be connected
    if (!udpLink->connect())
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not connect UDP port. Is an instance of " + qAppName() + "already running?");
        msgBox.setInformativeText("You will not be able to receive data via UDP. Please check that you're running the right executable and then re-start " + qAppName() + ". Do you want to close the application?");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        int ret = msgBox.exec();

        // Close the message box shortly after the click to prevent accidental clicks
        QTimer::singleShot(15000, &msgBox, SLOT(reject()));

        // Exit application
        if (ret == QMessageBox::Yes)
        {
            //mainWindow->close();
            QTimer::singleShot(200, mainWindow, SLOT(close()));
        }
    }

//    forever
//    {
//        QGC::SLEEP::msleep(5000);
//    }

//    mainWindow->close();
//    mainWindow->deleteLater();
//    QGC::SLEEP::msleep(200);
}

/**
 * @brief Destructor for the groundstation. It destroys all loaded instances.
 *
 **/
QGCCore::~QGCCore()
{
    //mainWindow->storeSettings();
    mainWindow->close();
    //mainWindow->deleteLater();
    // Delete singletons
	delete MainWindow::instance();
    delete LinkManager::instance();
    delete UASManager::instance();
}

/**
 * @brief Start the link managing component.
 *
 * The link manager keeps track of all communication links and provides the global
 * packet queue. It is the main communication hub
 **/
void QGCCore::startLinkManager()
{
    LinkManager::instance();
}

/**
 * @brief Start the Unmanned Air System Manager
 *
 **/
void QGCCore::startUASManager()
{
    // Load UAS plugins
    QDir pluginsDir = QDir(qApp->applicationDirPath());

#if defined(Q_OS_WIN)
    if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
        pluginsDir.cdUp();
#elif defined(Q_OS_LINUX)
    if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
        pluginsDir.cdUp();
#elif defined(Q_OS_MAC)
    if (pluginsDir.dirName() == "MacOS") {
        pluginsDir.cdUp();
        pluginsDir.cdUp();
        pluginsDir.cdUp();
    }
#endif
    pluginsDir.cd("plugins");

    UASManager::instance();

    // Load plugins

    QStringList pluginFileNames;

    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = loader.instance();
        if (plugin) {
            //populateMenus(plugin);
            pluginFileNames += fileName;
            //printf(QString("Loaded plugin from " + fileName + "\n").toStdString().c_str());
        }
    }
}

<|endoftext|>


<commit_before>#include <cassert>
#include <cstdlib>
#include "Reader.h"
#include "HdfReader.h"
#include "TextReader.h"
#include "VtkReader.h"

using namespace cigma;

// ---------------------------------------------------------------------------

void new_reader(cigma::Reader **reader, std::string ext)
{
    if (ext == ".h5")
    {
        *reader = new HdfReader();
        return;
    }

    if (ext == ".txt")
    {
        *reader = new TextReader();
        return;
    }

    if (ext == ".vtk")
    {
        *reader = new VtkReader();
        return;
    }

}

// ---------------------------------------------------------------------------

cigma::Reader::Reader()
{
}

cigma::Reader::~Reader()
{
}

// ---------------------------------------------------------------------------
<commit_msg>Instantiate a VtkXmlReader when given a file with a .vts (or .vtu) extension<commit_after>#include <cassert>
#include <cstdlib>
#include "Reader.h"
#include "HdfReader.h"
#include "TextReader.h"
#include "VtkReader.h"
#include "VtkXmlReader.h"

using namespace cigma;

// ---------------------------------------------------------------------------

void new_reader(cigma::Reader **reader, std::string ext)
{
    if (ext == ".h5")
    {
        *reader = new HdfReader();
        return;
    }

    if (ext == ".txt")
    {
        *reader = new TextReader();
        return;
    }

    if (ext == ".vtk")
    {
        // XXX: instantiate legacy vtk reader
        *reader = new VtkReader();
        return;
    }

    if ((ext == ".vts") || (ext == ".vtu"))
    {
        // XXX instantiate xml vtk reader
        *reader = new VtkXmlReader();
        if (ext == ".vtu")
        {
            // XXX: unstructured .vtu file reader still needed...so just fail for now
            assert(false);
        }
        return;
    }
}

// ---------------------------------------------------------------------------

cigma::Reader::Reader()
{
}

cigma::Reader::~Reader()
{
}

// ---------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: global.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: tbe $ $Date: 2001-05-11 09:01:30 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _OSL_PROCESS_H_
#include <osl/process.h>
#endif
#ifndef _RTL_OSTRINGBUFFER_HXX_
#include <rtl/strbuf.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#include <stdlib.h>
#include <stdio.h>
#if defined(SAL_W32) || defined(SAL_OS2)
#include <io.h>
#include <direct.h>
#include <errno.h>
#endif

#ifdef UNX
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#endif

#ifndef _CODEMAKER_GLOBAL_HXX_
#include    <codemaker/global.hxx>
#endif

using namespace rtl;

OString makeTempName(sal_Char* prefix)
{
    static OUString uTMP( RTL_CONSTASCII_USTRINGPARAM("TMP") );
    static OUString uTEMP( RTL_CONSTASCII_USTRINGPARAM("TEMP") );
    OUString        uPrefix( RTL_CONSTASCII_USTRINGPARAM("cmk_") );
    OUString        uPattern;

    sal_Char*   pPrefix = "cmk_";
    sal_Char    tmpPattern[512];
    sal_Char    *pTmpName = NULL;

    if (prefix)
        pPrefix = prefix;

    if ( osl_getEnvironment(uTMP.pData, &uPattern.pData) != osl_Process_E_None )
    {
        if ( osl_getEnvironment(uTEMP.pData, &uPattern.pData) != osl_Process_E_None )
        {
#if defined(SAL_W32) || defined(SAL_OS2)
            strcpy(tmpPattern, ".");
#else
            strcpy(tmpPattern, "/tmp");
#endif
        }
    }

    if (uPattern.getLength())
    {
        strcpy(tmpPattern, OUStringToOString(uPattern, RTL_TEXTENCODING_UTF8).getStr());
    }

#ifdef SAL_W32
    strcat(tmpPattern, "\\");
    strcat(tmpPattern, pPrefix);
    strcat(tmpPattern, "XXXXXX");
    pTmpName = mktemp(tmpPattern);
#endif

#ifdef SAL_OS2
    strcpy(tmpPattern, tempnam(NULL, prefix);
    pTmpName = tmpPattern;
#endif

#ifdef SAL_UNX
    strcat(tmpPattern, "\\");
    strcat(tmpPattern, pPrefix);
    strcat(tmpPattern, "XXXXXX");
    pTmpName = mktemp(tmpPattern);
#endif

    return OString(pTmpName);
}

OString createFileNameFromType( const OString& destination,
                                const OString typeName,
                                const OString postfix,
                                sal_Bool bLowerCase,
                                const OString prefix )
{
    OString type(typeName);

    if (bLowerCase)
    {
        type = typeName.toAsciiLowerCase();
    }

    sal_uInt32 length = destination.getLength();

    sal_Bool withPoint = sal_False;
    if (length == 0)
    {
        length++;
        withPoint = sal_True;
    }

    length += prefix.getLength() + type.getLength() + postfix.getLength();

    sal_Bool withSeperator = sal_False;
    if (destination.getStr()[destination.getLength()] != '\\' &&
        destination.getStr()[destination.getLength()] != '/' &&
        type.getStr()[0] != '\\' &&
        type.getStr()[0] != '/')
    {
        length++;
        withSeperator = sal_True;
    }

    OStringBuffer nameBuffer(length);

    if (withPoint)
        nameBuffer.append('.');
    else
        nameBuffer.append(destination.getStr(), destination.getLength());

    if (withSeperator)
        nameBuffer.append("/", 1);

    OString tmpStr(type);
    if (prefix.getLength() > 0)
    {
        tmpStr = type.replaceAt(type.lastIndexOf('/')+1, 0, prefix);
    }

    nameBuffer.append(tmpStr.getStr(), tmpStr.getLength());
    nameBuffer.append(postfix.getStr(), postfix.getLength());

    OString fileName(nameBuffer);

    sal_Char token;
#ifdef SAL_UNX
    fileName = fileName.replace('\\', '/');
    token = '/';
#else
    fileName = fileName.replace('/', '\\');
    token = '\\';
#endif

    nameBuffer = OStringBuffer(length);

    sal_Int32 nIndex = 0;
    do
    {
        nameBuffer.append(fileName.getToken( 0, token, nIndex ).getStr());

        if (nameBuffer.getLength() == 0 || OString(".") == nameBuffer.getStr())
        {
            nameBuffer.append(token);
            continue;
        }

#ifdef SAL_UNX
        if (mkdir((char*)nameBuffer.getStr(), 0777) == -1)
#else
           if (mkdir((char*)nameBuffer.getStr()) == -1)
#endif
        {
// #if __SUNPRO_CC >= 0x500
//          if( * ::___errno() == ENOENT )
// #else
            if ( errno == ENOENT )
// #endif
                return OString();
        }

        nameBuffer.append(token);
    }
    while ( nIndex >= 0 );

    return fileName;
}

sal_Bool fileExists(const OString& fileName)
{
    FILE  *f= fopen(fileName.getStr(), "r");

    if (f != NULL)
    {
        fclose(f);
        return sal_True;
    }

    return sal_False;
}

sal_Bool checkFileContent(const OString& targetFileName, const OString& tmpFileName)
{
    FILE  *target = fopen(targetFileName.getStr(), "r");
    FILE  *tmp = fopen(tmpFileName.getStr(), "r");
    sal_Bool ret = sal_False;

    if (target != NULL && tmp != NULL)
    {
        sal_Bool    bFindChanges = sal_False;
        sal_Char    buffer1[1024+1];
        sal_Char    buffer2[1024+1];
        sal_Int32   n1 = 0;
        sal_Int32   n2 = 0;

        while ( !bFindChanges && !feof(target) && !feof(tmp))
        {
            n1 = fread(buffer1, sizeof(sal_Char), 1024, target);
            n2 = fread(buffer2, sizeof(sal_Char), 1024, tmp);

            if ( n1 != n2 )
            {
                bFindChanges = sal_True;
            }
            else
            {
                if ( rtl_compareMemory(buffer1, buffer2, n2) != 0 )
                    bFindChanges =  sal_True;
            }
        }

        fclose(target);
        fclose(tmp);

        if ( bFindChanges )
        {
            if ( !unlink(targetFileName.getStr()) )
                if ( !rename(targetFileName.getStr(), tmpFileName.getStr()) )
                    ret = sal_True;
        }
        else
        {
            if ( !unlink(tmpFileName.getStr()) )
                ret = sal_True;
        }
    }

    return ret;
}

const OString inGlobalSet(const OUString & rValue)
{
    OString sValue( OUStringToOString(rValue, RTL_TEXTENCODING_UTF8) );
    static StringSet aGlobalMap;
    StringSet::iterator iter = aGlobalMap.find( sValue );
    if( iter != aGlobalMap.end() )
        return *iter;
    return *(aGlobalMap.insert( sValue ).first);
}

//*************************************************************************
// FileStream
//*************************************************************************
FileStream::FileStream()
{
}

FileStream::FileStream(const OString& name, sal_Int32 nMode)
    : ofstream(name, nMode)
    , m_name(name)
{
}

FileStream::~FileStream()
{
    flush();
    close();
}

sal_Bool FileStream::isValid()
{
#if defined(SAL_UNX) || defined(SAL_OS2)
#if STLPORT_VERSION < 400
    if(rdbuf()->fd() < 0)
#else
    if( !is_open() )
#endif
#else
    if(fd() < 0)
#endif
    {
        return sal_False;
    }

    return sal_True;
}

void FileStream::openFile(const OString& name, sal_Int32 nMode)
{
    if ( name.getLength() > 0 )
        m_name = name;

    if ( m_name.getLength() > 0 )
        open(m_name, nMode);
}

void FileStream::closeFile()
{
    flush();
    close();
}

sal_Int32 FileStream::getSize()
{
    flush();

    FILE* f = fopen(m_name, "r");
    sal_Int32 size = 0;
    if (!fseek(f, 0, SEEK_END))
        size = ftell(f);
    fclose(f);
    return size;
}

<commit_msg>#87298#<commit_after>/*************************************************************************
 *
 *  $RCSfile: global.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hjs $ $Date: 2001-07-18 18:02:39 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _OSL_PROCESS_H_
#include <osl/process.h>
#endif
#ifndef _RTL_OSTRINGBUFFER_HXX_
#include <rtl/strbuf.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#include <stdlib.h>
#include <stdio.h>
#if defined(SAL_W32) || defined(SAL_OS2)
#include <io.h>
#include <direct.h>
#include <errno.h>
#endif

#ifdef UNX
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#endif

#ifndef _CODEMAKER_GLOBAL_HXX_
#include    <codemaker/global.hxx>
#endif

using namespace rtl;

OString makeTempName(sal_Char* prefix)
{
    static OUString uTMP( RTL_CONSTASCII_USTRINGPARAM("TMP") );
    static OUString uTEMP( RTL_CONSTASCII_USTRINGPARAM("TEMP") );
    OUString        uPrefix( RTL_CONSTASCII_USTRINGPARAM("cmk_") );
    OUString        uPattern;

    sal_Char*   pPrefix = "cmk_";
    sal_Char    tmpPattern[512];
    sal_Char    *pTmpName = NULL;

    if (prefix)
        pPrefix = prefix;

    if ( osl_getEnvironment(uTMP.pData, &uPattern.pData) != osl_Process_E_None )
    {
        if ( osl_getEnvironment(uTEMP.pData, &uPattern.pData) != osl_Process_E_None )
        {
#if defined(SAL_W32) || defined(SAL_OS2)
            strcpy(tmpPattern, ".");
#else
            strcpy(tmpPattern, "/tmp");
#endif
        }
    }

    if (uPattern.getLength())
    {
        strcpy(tmpPattern, OUStringToOString(uPattern, RTL_TEXTENCODING_UTF8).getStr());
    }

#ifdef SAL_W32
    strcat(tmpPattern, "\\");
    strcat(tmpPattern, pPrefix);
    strcat(tmpPattern, "XXXXXX");
    pTmpName = mktemp(tmpPattern);
#endif

#ifdef SAL_OS2
    strcpy(tmpPattern, tempnam(NULL, prefix);
    pTmpName = tmpPattern;
#endif

#ifdef SAL_UNX
    strcat(tmpPattern, "\\");
    strcat(tmpPattern, pPrefix);
    strcat(tmpPattern, "XXXXXX");
    pTmpName = mktemp(tmpPattern);
#endif

    return OString(pTmpName);
}

OString createFileNameFromType( const OString& destination,
                                const OString typeName,
                                const OString postfix,
                                sal_Bool bLowerCase,
                                const OString prefix )
{
    OString type(typeName);

    if (bLowerCase)
    {
        type = typeName.toAsciiLowerCase();
    }

    sal_uInt32 length = destination.getLength();

    sal_Bool withPoint = sal_False;
    if (length == 0)
    {
        length++;
        withPoint = sal_True;
    }

    length += prefix.getLength() + type.getLength() + postfix.getLength();

    sal_Bool withSeperator = sal_False;
    if (destination.getStr()[destination.getLength()] != '\\' &&
        destination.getStr()[destination.getLength()] != '/' &&
        type.getStr()[0] != '\\' &&
        type.getStr()[0] != '/')
    {
        length++;
        withSeperator = sal_True;
    }

    OStringBuffer nameBuffer(length);

    if (withPoint)
        nameBuffer.append('.');
    else
        nameBuffer.append(destination.getStr(), destination.getLength());

    if (withSeperator)
        nameBuffer.append("/", 1);

    OString tmpStr(type);
    if (prefix.getLength() > 0)
    {
        tmpStr = type.replaceAt(type.lastIndexOf('/')+1, 0, prefix);
    }

    nameBuffer.append(tmpStr.getStr(), tmpStr.getLength());
    nameBuffer.append(postfix.getStr(), postfix.getLength());

    OString fileName(nameBuffer);

    sal_Char token;
#ifdef SAL_UNX
    fileName = fileName.replace('\\', '/');
    token = '/';
#else
    fileName = fileName.replace('/', '\\');
    token = '\\';
#endif

    nameBuffer = OStringBuffer(length);

    sal_Int32 nIndex = 0;
    do
    {
        nameBuffer.append(fileName.getToken( 0, token, nIndex ).getStr());

        if (nameBuffer.getLength() == 0 || OString(".") == nameBuffer.getStr())
        {
            nameBuffer.append(token);
            continue;
        }

#ifdef SAL_UNX
        if (mkdir((char*)nameBuffer.getStr(), 0777) == -1)
#else
           if (mkdir((char*)nameBuffer.getStr()) == -1)
#endif
        {
// #if __SUNPRO_CC >= 0x500
//          if( * ::___errno() == ENOENT )
// #else
            if ( errno == ENOENT )
// #endif
                return OString();
        }

        nameBuffer.append(token);
    }
    while ( nIndex >= 0 );

    return fileName;
}

sal_Bool fileExists(const OString& fileName)
{
    FILE  *f= fopen(fileName.getStr(), "r");

    if (f != NULL)
    {
        fclose(f);
        return sal_True;
    }

    return sal_False;
}

sal_Bool checkFileContent(const OString& targetFileName, const OString& tmpFileName)
{
    FILE  *target = fopen(targetFileName.getStr(), "r");
    FILE  *tmp = fopen(tmpFileName.getStr(), "r");
    sal_Bool ret = sal_False;

    if (target != NULL && tmp != NULL)
    {
        sal_Bool    bFindChanges = sal_False;
        sal_Char    buffer1[1024+1];
        sal_Char    buffer2[1024+1];
        sal_Int32   n1 = 0;
        sal_Int32   n2 = 0;

        while ( !bFindChanges && !feof(target) && !feof(tmp))
        {
            n1 = fread(buffer1, sizeof(sal_Char), 1024, target);
            n2 = fread(buffer2, sizeof(sal_Char), 1024, tmp);

            if ( n1 != n2 )
            {
                bFindChanges = sal_True;
            }
            else
            {
                if ( rtl_compareMemory(buffer1, buffer2, n2) != 0 )
                    bFindChanges =  sal_True;
            }
        }

        fclose(target);
        fclose(tmp);

        if ( bFindChanges )
        {
            if ( !unlink(targetFileName.getStr()) )
                if ( !rename(targetFileName.getStr(), tmpFileName.getStr()) )
                    ret = sal_True;
        }
        else
        {
            if ( !unlink(tmpFileName.getStr()) )
                ret = sal_True;
        }
    }

    return ret;
}

const OString inGlobalSet(const OUString & rValue)
{
    OString sValue( OUStringToOString(rValue, RTL_TEXTENCODING_UTF8) );
    static StringSet aGlobalMap;
    StringSet::iterator iter = aGlobalMap.find( sValue );
    if( iter != aGlobalMap.end() )
        return *iter;
    return *(aGlobalMap.insert( sValue ).first);
}

//*************************************************************************
// FileStream
//*************************************************************************
FileStream::FileStream()
{
}

FileStream::FileStream(const OString& name, sal_Int32 nMode)
    : ofstream(name, nMode)
    , m_name(name)
{
}

FileStream::~FileStream()
{
    flush();
    close();
}

sal_Bool FileStream::isValid()
{
#ifndef __STL_NO_NEW_IOSTREAMS
#if STLPORT_VERSION < 400
    if(rdbuf()->fd() < 0)
#else
    if( !is_open() )
#endif
#else
    if(fd() < 0)
#endif
    {
        return sal_False;
    }

    return sal_True;
}

void FileStream::openFile(const OString& name, sal_Int32 nMode)
{
    if ( name.getLength() > 0 )
        m_name = name;

    if ( m_name.getLength() > 0 )
        open(m_name, nMode);
}

void FileStream::closeFile()
{
    flush();
    close();
}

sal_Int32 FileStream::getSize()
{
    flush();

    FILE* f = fopen(m_name, "r");
    sal_Int32 size = 0;
    if (!fseek(f, 0, SEEK_END))
        size = ftell(f);
    fclose(f);
    return size;
}

<|endoftext|>


<commit_before>
#include "test_precomp.hpp"

#include <string>
#include <fstream>
#include <iostream>

#include "cvext_c.h"

typedef void (*CvActivationFunc)(CvMat *, CvMat *);
// typedef void (CV_CDECL *CvCNNLayerForward)
//     ( CvCNNLayer* layer, const CvMat* X, CvMat* Y );
// typedef void (CV_CDECL *CvCNNLayerBackward)
//     ( CvCNNLayer* layer, int t, const CvMat* X, const CvMat* dE_dY, CvMat* dE_dX);

void cvActivationGradCheck(CvActivationFunc actfunc, CvActivationFunc actfunc_der)
{
  int nr=100, nc=100;
  const float eps = 1e-4f;
  CvMat * src = cvCreateMat(nr,nc,CV_32F);
  CvMat * src_more = cvCreateMat(nr,nc,CV_32F);
  CvMat * src_less = cvCreateMat(nr,nc,CV_32F);
  CvMat * dst = cvCreateMat(nr,nc,CV_32F);
  CvMat * dst_more = cvCreateMat(nr,nc,CV_32F);
  CvMat * dst_less = cvCreateMat(nr,nc,CV_32F);
  CvMat * diff = cvCreateMat(nr,nc,CV_32F);
  CvMat * grad = cvCreateMat(nr,nc,CV_32F);
  CvMat * src_der = cvCreateMat(nr,nc,CV_32F);
  CvMat * rel_error = cvCreateMat(nr,nc,CV_32F);
  CvMat * sum_error = cvCreateMat(nr,nc,CV_32F);
  CvRNG rng = cvRNG(-1);
  cvRandArr(&rng,src,CV_RAND_UNI,cvScalar(-5),cvScalar(5));
  cvAddS(src,cvScalar(eps),src_more);
  cvAddS(src,cvScalar(-eps),src_less);
  cvZero(dst); cvZero(dst_more); cvZero(dst_less);
  actfunc(src,dst);
  actfunc(src_more,dst_more);
  actfunc(src_less,dst_less);
  cvSub(dst_more,dst_less,diff);
  cvScale(diff,grad,1./(2.f*eps));
  actfunc_der(src,src_der);
  cvSub(grad,src_der,rel_error); cvAbs(rel_error,rel_error);
  // cvAdd(grad,src_der,sum_error); cvAbs(sum_error,sum_error); cvAddS(sum_error,cvScalar(1e-5),sum_error);
  // cvDiv(rel_error,sum_error,rel_error);
  EXPECT_LT(cvNorm(rel_error,0,CV_C), 0.001);
  EXPECT_LT(cvNorm(rel_error,0,CV_L1)/(nr*nc), 0.001);
}

void cvCNNLayerGradCheck(CvCNNLayer * layer, CvMat * X, CvMat * Y, CvMat * target,
                         CvMat * grad0, CvMat * grad1, int norm_type)
{
  const float eps = 1e-4;
  CvMat * weights = cvCloneMat(layer->weights);
  CvMat * Y_less = cvCloneMat(Y), * Y_more = cvCloneMat(Y);
  CvMat * dE_dY = cvCreateMat(Y->cols,Y->rows,CV_32F);
  CvMat * dE_dX = cvCreateMat(X->cols,X->rows,CV_32F);
  cvCopy(weights,layer->weights);
  layer->forward(layer,X,Y); cvTranspose(target,dE_dY); cvAdd(Y,target,target); cvScale(dE_dY,dE_dY,-1.f);
  layer->backward(layer,1,X,dE_dY,dE_dX); cvCopy(layer->dE_dW,grad1);
  for (int ridx=0;ridx<layer->weights->rows;ridx++){
  for (int cidx=0;cidx<layer->weights->cols;cidx++){
    // weights(ridx,cidx) + eps
    cvCopy(weights,layer->weights); CV_MAT_ELEM(*layer->weights,float,ridx,cidx)+=eps;
    layer->forward(layer,X,Y_more); cvSub(Y_more,target,Y_more); float Y_more_loss=cvNorm(Y_more,0,norm_type);
    // weights(ridx,cidx) - eps
    cvCopy(weights,layer->weights); CV_MAT_ELEM(*layer->weights,float,ridx,cidx)-=eps;
    layer->forward(layer,X,Y_less); cvSub(Y_less,target,Y_less); float Y_less_loss=cvNorm(Y_less,0,norm_type);
    CV_MAT_ELEM(*grad0,float,ridx,cidx) = (Y_more_loss-Y_less_loss)/(2.f*eps);
  }
  }
  cvReleaseMat(&weights);
  cvReleaseMat(&Y_more);
  cvReleaseMat(&Y_less);
  cvReleaseMat(&dE_dY);
  cvReleaseMat(&dE_dX);
}

/////////////////////////////////////////////////////////////////////////////
//////////////////// test registration  /////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

TEST(ML_Tanh, gradcheck){cvActivationGradCheck(cvTanh, cvTanhDer);}
TEST(ML_Sigmoid, gradcheck){cvActivationGradCheck(cvSigmoid, cvSigmoidDer);}
TEST(ML_ReLU, gradcheck){cvActivationGradCheck(cvReLU, cvReLUDer);}
TEST(ML_Softmax, gradcheck){cvActivationGradCheck(cvSoftmax, cvSoftmaxDer);}

TEST(ML_ConvolutionLayer, gradcheck){
  const float eps = 1e-4;
  const int n_inputs = 2;
  const int n_outputs = 6;
  const int imsize = 20;
  const int ksize = 3;
  const int batch_size = 2;
  const int imsize_out = imsize-ksize+1;
  CvCNNLayer * layer = cvCreateCNNConvolutionLayer("conv1",0,n_inputs,imsize,imsize,n_outputs,ksize,.01,1,0,0);
  CvMat * X = cvCreateMat(imsize*imsize*n_inputs,batch_size,CV_32F);
  CvMat * Y = cvCreateMat(imsize_out*imsize_out*n_outputs,batch_size,CV_32F);
  CvMat * target = cvCreateMat(imsize_out*imsize_out*n_outputs,batch_size,CV_32F);
  CvMat * grad0 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * grad1 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * norm = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvRNG rng = cvRNG(-1);
  cvRandArr(&rng,X,CV_RAND_UNI,cvScalar(-3),cvScalar(3));
  cvRandArr(&rng,target,CV_RAND_NORMAL,cvScalar(0),cvScalar(.1));
  cvCNNLayerGradCheck(layer, X, Y, target, grad0, grad1, CV_L1);
  fprintf(stderr,"\ngrad0:\n");cvPrintf(stderr,"%.2f ",grad0);
  fprintf(stderr,"\ngrad1:\n");cvPrintf(stderr,"%.2f ",grad1);
  for (int ridx=0;ridx<grad0->rows;ridx++){
  for (int cidx=0;cidx<grad0->cols;cidx++){
    float gval0 = CV_MAT_ELEM(*grad0,float,ridx,cidx);
    float gval1 = CV_MAT_ELEM(*grad1,float,ridx,cidx);
    CV_MAT_ELEM(*norm,float,ridx,cidx)=fabs(gval0-gval1)/(fabs(gval0)+fabs(gval1)+1e-5f);
  }
  }
  fprintf(stderr,"\nrel_error:\n");cvPrintf(stderr,"%.2f ",norm);
  fprintf(stderr,"\nquantile [10%%]:%f",cvQuantile(norm,.1));
  fprintf(stderr,"\nquantile [50%%]:%f",cvQuantile(norm,.5));
  fprintf(stderr,"\nquantile [60%%]:%f",cvQuantile(norm,.6));
  fprintf(stderr,"\nquantile [70%%]:%f",cvQuantile(norm,.7));
  fprintf(stderr,"\nquantile [80%%]:%f",cvQuantile(norm,.8));
  fprintf(stderr,"\nquantile [90%%]:%f\n",cvQuantile(norm,.9));
  EXPECT_LT(cvQuantile(norm,.6),1.f);
  cvReleaseMat(&X);
  cvReleaseMat(&Y);
  cvReleaseMat(&target);
  cvReleaseMat(&grad0);
  cvReleaseMat(&grad1);
  cvReleaseMat(&norm);
}

TEST(ML_FullConnectLayer, gradcheck){
  const float eps = 1e-4;
  const int n_inputs = 20;
  const int n_outputs = 10;
  const int batch_size = 2;
  CvCNNLayer * layer = cvCreateCNNFullConnectLayer("fc1",0,0,n_inputs,n_outputs,.01,1,"tanh",0);
  ASSERT_TRUE(ICV_IS_CNN_FULLCONNECT_LAYER(layer));
  CvMat * X = cvCreateMat(n_inputs,batch_size,CV_32F);
  CvMat * Y = cvCreateMat(n_outputs,batch_size,CV_32F);
  CvMat * target = cvCreateMat(Y->rows,Y->cols,CV_32F);
  CvMat * grad0 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * grad1 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * norm = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvRNG rng = cvRNG(-1);
  cvRandArr(&rng,X,CV_RAND_UNI,cvScalar(-2),cvScalar(2));
  cvRandArr(&rng,target,CV_RAND_UNI,cvScalar(-.2),cvScalar(.2));
  cvCNNLayerGradCheck(layer, X, Y, target, grad0, grad1, CV_L2);
  for (int ridx=0;ridx<grad0->rows;ridx++){
  for (int cidx=0;cidx<grad0->cols;cidx++){
    float gval0 = CV_MAT_ELEM(*grad0,float,ridx,cidx);
    float gval1 = CV_MAT_ELEM(*grad1,float,ridx,cidx);
    CV_MAT_ELEM(*norm,float,ridx,cidx)=fabs(gval0-gval1)/(fabs(gval0)+fabs(gval1)+1e-5f);
  }
  }
  fprintf(stderr,"quantile [90%%]:%f\n",cvQuantile(norm,.9));
  EXPECT_LT(cvQuantile(norm,.9),.1f);
  cvReleaseMat(&X);
  cvReleaseMat(&Y);
  cvReleaseMat(&target);
  cvReleaseMat(&grad0);
  cvReleaseMat(&grad1);
  cvReleaseMat(&norm);
}

<commit_msg>gradient checking;<commit_after>
#include "test_precomp.hpp"

#include <string>
#include <fstream>
#include <iostream>

#include "cvext_c.h"

typedef void (*CvActivationFunc)(CvMat *, CvMat *);
// typedef void (CV_CDECL *CvCNNLayerForward)
//     ( CvCNNLayer* layer, const CvMat* X, CvMat* Y );
// typedef void (CV_CDECL *CvCNNLayerBackward)
//     ( CvCNNLayer* layer, int t, const CvMat* X, const CvMat* dE_dY, CvMat* dE_dX);

void cvActivationGradCheck(CvActivationFunc actfunc, CvActivationFunc actfunc_der)
{
  int nr=100, nc=100;
  const float eps = 1e-4f;
  CvMat * src = cvCreateMat(nr,nc,CV_32F);
  CvMat * src_more = cvCreateMat(nr,nc,CV_32F);
  CvMat * src_less = cvCreateMat(nr,nc,CV_32F);
  CvMat * dst = cvCreateMat(nr,nc,CV_32F);
  CvMat * dst_more = cvCreateMat(nr,nc,CV_32F);
  CvMat * dst_less = cvCreateMat(nr,nc,CV_32F);
  CvMat * diff = cvCreateMat(nr,nc,CV_32F);
  CvMat * grad = cvCreateMat(nr,nc,CV_32F);
  CvMat * src_der = cvCreateMat(nr,nc,CV_32F);
  CvMat * rel_error = cvCreateMat(nr,nc,CV_32F);
  CvMat * sum_error = cvCreateMat(nr,nc,CV_32F);
  CvRNG rng = cvRNG(-1);
  cvRandArr(&rng,src,CV_RAND_UNI,cvScalar(-5),cvScalar(5));
  cvAddS(src,cvScalar(eps),src_more);
  cvAddS(src,cvScalar(-eps),src_less);
  cvZero(dst); cvZero(dst_more); cvZero(dst_less);
  actfunc(src,dst);
  actfunc(src_more,dst_more);
  actfunc(src_less,dst_less);
  cvSub(dst_more,dst_less,diff);
  cvScale(diff,grad,1./(2.f*eps));
  actfunc_der(src,src_der);
  cvSub(grad,src_der,rel_error); cvAbs(rel_error,rel_error);
  // cvAdd(grad,src_der,sum_error); cvAbs(sum_error,sum_error); cvAddS(sum_error,cvScalar(1e-5),sum_error);
  // cvDiv(rel_error,sum_error,rel_error);
  EXPECT_LT(cvNorm(rel_error,0,CV_C), 0.001);
  EXPECT_LT(cvNorm(rel_error,0,CV_L1)/(nr*nc), 0.001);
}

void cvCNNLayerGradCheck(CvCNNLayer * layer, CvMat * X, CvMat * Y, CvMat * target,
                         CvMat * grad0, CvMat * grad1, int norm_type)
{
  const float eps = 1e-4;
  CvMat * weights = cvCloneMat(layer->weights);
  CvMat * Y_less = cvCloneMat(Y), * Y_more = cvCloneMat(Y);
  CvMat * dE_dY = cvCreateMat(Y->cols,Y->rows,CV_32F);
  CvMat * dE_dX = cvCreateMat(X->cols,X->rows,CV_32F);
  cvCopy(weights,layer->weights);
  layer->forward(layer,X,Y); cvTranspose(target,dE_dY); cvAdd(Y,target,target); cvScale(dE_dY,dE_dY,-1.f);
  layer->backward(layer,1,X,dE_dY,dE_dX); cvCopy(layer->dE_dW,grad1);
  for (int ridx=0;ridx<layer->weights->rows;ridx++){
  for (int cidx=0;cidx<layer->weights->cols;cidx++){
    // weights(ridx,cidx) + eps
    cvCopy(weights,layer->weights); CV_MAT_ELEM(*layer->weights,float,ridx,cidx)+=eps;
    layer->forward(layer,X,Y_more); cvSub(Y_more,target,Y_more); float Y_more_loss=cvNorm(Y_more,0,norm_type);
    // weights(ridx,cidx) - eps
    cvCopy(weights,layer->weights); CV_MAT_ELEM(*layer->weights,float,ridx,cidx)-=eps;
    layer->forward(layer,X,Y_less); cvSub(Y_less,target,Y_less); float Y_less_loss=cvNorm(Y_less,0,norm_type);
    CV_MAT_ELEM(*grad0,float,ridx,cidx) = (Y_more_loss-Y_less_loss)/(2.f*eps);
  }
  }
  cvReleaseMat(&weights);
  cvReleaseMat(&Y_more);
  cvReleaseMat(&Y_less);
  cvReleaseMat(&dE_dY);
  cvReleaseMat(&dE_dX);
}

/////////////////////////////////////////////////////////////////////////////
//////////////////// test registration  /////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

TEST(ML_Tanh, gradcheck){cvActivationGradCheck(cvTanh, cvTanhDer);}
TEST(ML_Sigmoid, gradcheck){cvActivationGradCheck(cvSigmoid, cvSigmoidDer);}
TEST(ML_ReLU, gradcheck){cvActivationGradCheck(cvReLU, cvReLUDer);}
TEST(ML_Softmax, gradcheck){cvActivationGradCheck(cvSoftmax, cvSoftmaxDer);}

TEST(ML_ConvolutionLayer, gradcheck){
  const float eps = 1e-4;
  const int n_inputs = 2;
  const int n_outputs = 6;
  const int imsize = 20;
  const int ksize = 3;
  const int batch_size = 2;
  const int imsize_out = imsize-ksize+1;
  CvCNNLayer * layer = cvCreateCNNConvolutionLayer("conv1",0,n_inputs,imsize,imsize,n_outputs,ksize,.01,1,0,0);
  CvMat * X = cvCreateMat(imsize*imsize*n_inputs,batch_size,CV_32F);
  CvMat * Y = cvCreateMat(imsize_out*imsize_out*n_outputs,batch_size,CV_32F);
  CvMat * target = cvCreateMat(imsize_out*imsize_out*n_outputs,batch_size,CV_32F);
  CvMat * grad0 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * grad1 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * norm = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvRNG rng = cvRNG(-1);
  cvRandArr(&rng,X,CV_RAND_UNI,cvScalar(-3),cvScalar(3));
  cvRandArr(&rng,target,CV_RAND_NORMAL,cvScalar(0),cvScalar(.1));
  cvCNNLayerGradCheck(layer, X, Y, target, grad0, grad1, CV_L1);
  fprintf(stderr,"\ngrad0:\n");cvPrintf(stderr,"%.2f ",grad0);
  fprintf(stderr,"\ngrad1:\n");cvPrintf(stderr,"%.2f ",grad1);
  for (int ridx=0;ridx<grad0->rows;ridx++){
  for (int cidx=0;cidx<grad0->cols;cidx++){
    float gval0 = CV_MAT_ELEM(*grad0,float,ridx,cidx);
    float gval1 = CV_MAT_ELEM(*grad1,float,ridx,cidx);
    CV_MAT_ELEM(*norm,float,ridx,cidx)=fabs(gval0-gval1)/(fabs(gval0)+fabs(gval1)+1e-5f);
  }
  }
  fprintf(stderr,"\nrel_error:\n");cvPrintf(stderr,"%.2f ",norm);
  fprintf(stderr,"\nquantile [10%%]:%f",cvQuantile(norm,.1));
  fprintf(stderr,"\nquantile [50%%]:%f",cvQuantile(norm,.5));
  fprintf(stderr,"\nquantile [60%%]:%f",cvQuantile(norm,.6));
  fprintf(stderr,"\nquantile [70%%]:%f",cvQuantile(norm,.7));
  fprintf(stderr,"\nquantile [80%%]:%f",cvQuantile(norm,.8));
  fprintf(stderr,"\nquantile [90%%]:%f\n",cvQuantile(norm,.9));
  EXPECT_LT(cvQuantile(norm,.9),.99f);
  cvReleaseMat(&X);
  cvReleaseMat(&Y);
  cvReleaseMat(&target);
  cvReleaseMat(&grad0);
  cvReleaseMat(&grad1);
  cvReleaseMat(&norm);
}

TEST(ML_FullConnectLayer, gradcheck){
  const float eps = 1e-4;
  const int n_inputs = 20;
  const int n_outputs = 10;
  const int batch_size = 2;
  CvCNNLayer * layer = cvCreateCNNFullConnectLayer("fc1",0,0,n_inputs,n_outputs,.01,1,"tanh",0);
  ASSERT_TRUE(ICV_IS_CNN_FULLCONNECT_LAYER(layer));
  CvMat * X = cvCreateMat(n_inputs,batch_size,CV_32F);
  CvMat * Y = cvCreateMat(n_outputs,batch_size,CV_32F);
  CvMat * target = cvCreateMat(Y->rows,Y->cols,CV_32F);
  CvMat * grad0 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * grad1 = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvMat * norm = cvCreateMat(layer->weights->rows,layer->weights->cols,CV_32F);
  CvRNG rng = cvRNG(-1);
  cvRandArr(&rng,X,CV_RAND_UNI,cvScalar(-2),cvScalar(2));
  cvRandArr(&rng,target,CV_RAND_UNI,cvScalar(-.2),cvScalar(.2));
  cvCNNLayerGradCheck(layer, X, Y, target, grad0, grad1, CV_L2);
  for (int ridx=0;ridx<grad0->rows;ridx++){
  for (int cidx=0;cidx<grad0->cols;cidx++){
    float gval0 = CV_MAT_ELEM(*grad0,float,ridx,cidx);
    float gval1 = CV_MAT_ELEM(*grad1,float,ridx,cidx);
    CV_MAT_ELEM(*norm,float,ridx,cidx)=fabs(gval0-gval1)/(fabs(gval0)+fabs(gval1)+1e-5f);
  }
  }
  fprintf(stderr,"quantile [90%%]:%f\n",cvQuantile(norm,.9));
  fprintf(stderr,"quantile [95%%]:%f\n",cvQuantile(norm,.95));
  EXPECT_LT(cvQuantile(norm,.95),.99f);
  cvReleaseMat(&X);
  cvReleaseMat(&Y);
  cvReleaseMat(&target);
  cvReleaseMat(&grad0);
  cvReleaseMat(&grad1);
  cvReleaseMat(&norm);
}

<|endoftext|>


<commit_before>#ifndef DTLS_HANDSHAKE_HPP
#define DTLS_HANDSHAKE_HPP

#include "dtls.hpp"

namespace DTLS {

namespace Handshake {
struct HandshakeType {
	static constexpr uint8_t helloRequest = 0;
	static constexpr uint8_t clientHello = 1;
	static constexpr uint8_t serverHello = 2;
	static constexpr uint8_t certificate = 11;
	static constexpr uint8_t serverKeyExchange = 12;
	static constexpr uint8_t certificateRequest = 13;
	static constexpr uint8_t serverHelloDone = 14;
	static constexpr uint8_t certificateVerify = 15;
	static constexpr uint8_t clientKeyExchange = 16;
	static constexpr uint8_t finished = 20;

	uint8_t val;

	void setHelloRequest() { val = helloRequest; };
	void setClientHello() { val = clientHello; };
	void setServerHello() { val = serverHello; };
	void setCertificate() { val = certificate; };
	void setServerKeyExchange() { val = serverKeyExchange; };
	void setCertificateRequest() { val = certificateRequest; };
	void setServerHelloDone() { val = serverHelloDone; };
	void setCertificateVerify() { val = certificateVerify; };
	void setClientKeyExchange() { val = clientKeyExchange; };
	void setFinished() { val = finished; };

	bool isHelloRequest() { return val == helloRequest; };
	bool isClientHello() { return val == clientHello; };
	bool isServerHello() { return val == serverHello; };
	bool isCertificate() { return val == certificate; };
	bool isServerKeyExchange() { return val == serverKeyExchange; };
	bool isCertificateRequest() { return val == certificateRequest; };
	bool isServerHelloDone() { return val == serverHelloDone; };
	bool isCertificateVerify() { return val == certificateVerify; };
	bool isClientKeyExchange() { return val == clientKeyExchange; };
	bool isFinished() { return val == finished; };
};

struct Header {
	HandshakeType msgType;
	uint24 length;
	uint16_t messageSeq;
	uint24 fragmentOffset;
	uint24 fragmentLength;
};

namespace Hello {};
namespace Certificate {};
namespace KeyExchange {};
namespace Finished {};

}; // namespace Handshake

}; // namespace DTLS

#endif /* DTLS_HANDSHAKE_HPP */
<commit_msg>add more dtls handshake<commit_after>#ifndef DTLS_HANDSHAKE_HPP
#define DTLS_HANDSHAKE_HPP

#include "dtls.hpp"

namespace DTLS {

namespace Handshake {
struct HandshakeType {
	static constexpr uint8_t helloRequest = 0;
	static constexpr uint8_t clientHello = 1;
	static constexpr uint8_t serverHello = 2;
	static constexpr uint8_t certificate = 11;
	static constexpr uint8_t serverKeyExchange = 12;
	static constexpr uint8_t certificateRequest = 13;
	static constexpr uint8_t serverHelloDone = 14;
	static constexpr uint8_t certificateVerify = 15;
	static constexpr uint8_t clientKeyExchange = 16;
	static constexpr uint8_t finished = 20;

	uint8_t val;

	void setHelloRequest() { val = helloRequest; };
	void setClientHello() { val = clientHello; };
	void setServerHello() { val = serverHello; };
	void setCertificate() { val = certificate; };
	void setServerKeyExchange() { val = serverKeyExchange; };
	void setCertificateRequest() { val = certificateRequest; };
	void setServerHelloDone() { val = serverHelloDone; };
	void setCertificateVerify() { val = certificateVerify; };
	void setClientKeyExchange() { val = clientKeyExchange; };
	void setFinished() { val = finished; };

	bool isHelloRequest() { return val == helloRequest; };
	bool isClientHello() { return val == clientHello; };
	bool isServerHello() { return val == serverHello; };
	bool isCertificate() { return val == certificate; };
	bool isServerKeyExchange() { return val == serverKeyExchange; };
	bool isCertificateRequest() { return val == certificateRequest; };
	bool isServerHelloDone() { return val == serverHelloDone; };
	bool isCertificateVerify() { return val == certificateVerify; };
	bool isClientKeyExchange() { return val == clientKeyExchange; };
	bool isFinished() { return val == finished; };
};

struct Header {
	HandshakeType msgType;
	uint24 length;
	uint16_t messageSeq;
	uint24 fragmentOffset;
	uint24 fragmentLength;
};

class ClientHello {
public:
	struct ClientHelloData {
		uint16_t client_version;
		uint8_t random[32];
		uint8_t sessionID[32];
		uint8_t sessionIDLength;
		uint8_t cookie[32];
		uint8_t cookieLength;

		struct CipherSuite {
			uint16_t data;
		};

		CipherSuite cipherSuites[128];
		uint8_t CipherSuiteNum;

		uint8_t compressionMethods[128];
		uint8_t compressionMethodsNum;
	};

	/*! Parses a Client hello message
	 *
	 * \param data payload to parse
	 * \param dataLen Length of the data field
	 * \param result struct to write the parsed data to
	 * \return Length of the ClientHello message
	 */
	static int parse(uint8_t *data, unsigned int dataLen, ClientHelloData &result);
};

class ServerHello {
public:
	struct ClientHelloData {
		uint16_t client_version;
		uint8_t random[32];
		uint8_t sessionID[32];
		uint8_t sessionIDLength;

		struct CipherSuite {
			uint16_t data;
		};

		CipherSuite cipherSuites;

		uint8_t compressionMethods;
	};

	/*! Parses a Client hello message
	 *
	 * \param data payload to parse
	 * \param dataLen Length of the data field
	 * \param result struct to write the parsed data to
	 * \return Length of the ClientHello message
	 */
	static int parse(uint8_t *data, unsigned int dataLen, ClientHelloData &result);
};

struct Certificate {
	uint8_t data[2048];
	uint16_t dataLen;
};

struct ServerKeyExchange {
	uint8_t Algorithm;
	uint8_t dh_p[512];
	uint8_t dh_g[512];
	uint8_t dh_Ys[512];
};
namespace Finished {};

}; // namespace Handshake

}; // namespace DTLS

#endif /* DTLS_HANDSHAKE_HPP */
<|endoftext|>


<commit_before>#ifndef TIME_UTILS_HPP_INCLUDED
#define TIME_UTILS_HPP_INCLUDED

/**
 @file time_utils.hpp
 @author François Becker

MIT License

Copyright (c) 2015-2017 François Becker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <ctime>
#include <cstdio>
#include <cstring>
#include <cassert>

namespace tu
{
    inline std::time_t timeFromYMDString(const char* pString)
    {
        // Time from YYYY-MM-DD
        int lYear, lMonth, lDay;
        sscanf(pString, "%d-%d-%d", &lYear, &lMonth, &lDay);
        struct tm t = {0};
        t.tm_year = lYear - 1900;
        t.tm_mon = lMonth - 1;
        t.tm_mday = lDay;
        t.tm_isdst = -1;
        return mktime(&t);
    }

    inline std::time_t timeFromYMDHMSString(const char* pString)
    {
        // Time from YYYY-mm-DD HH:MM:SS
        int lYear, lMonth, lDay, lHour, lMinute, lSecond;
        sscanf(pString, "%d-%d-%d %d:%d:%d", &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond);
        struct tm t = {0};
        t.tm_year = lYear - 1900;
        t.tm_mon = lMonth - 1;
        t.tm_mday = lDay;
        t.tm_hour = lHour;
        t.tm_min = lMinute;
        t.tm_sec = lSecond;
        t.tm_isdst = -1;
        return mktime(&t);
    }

    inline std::time_t timeFromStringDate(const char *time)
    {
        char s_month[5];
        int month, day, year;
        struct tm t = {0};
        static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

        sscanf(time, "%s %d %d", s_month, &day, &year);

        month = (int)(strstr(month_names, s_month)-month_names)/3;

        t.tm_mon = month;
        t.tm_mday = day;
        t.tm_year = year - 1900;
        t.tm_isdst = -1;

        return mktime(&t);
    }
}

#endif
<commit_msg>Added fbu::time::secondsSinceEpoch(), renamed namespace 'tu' to 'fbu::time'.<commit_after>#ifndef TIME_UTILS_HPP_INCLUDED
#define TIME_UTILS_HPP_INCLUDED

/**
 @file time_utils.hpp
 @author François Becker

MIT License

Copyright (c) 2015-2017 François Becker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <chrono>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cassert>

namespace fbu
{
    namespace time
    {
        inline std::time_t timeFromYMDString(const char* pString)
        {
            // Time from YYYY-MM-DD
            int lYear, lMonth, lDay;
            sscanf(pString, "%d-%d-%d", &lYear, &lMonth, &lDay);
            struct tm t = {0};
            t.tm_year = lYear - 1900;
            t.tm_mon = lMonth - 1;
            t.tm_mday = lDay;
            t.tm_isdst = -1;
            return mktime(&t);
        }

        inline std::time_t timeFromYMDHMSString(const char* pString)
        {
            // Time from YYYY-mm-DD HH:MM:SS
            int lYear, lMonth, lDay, lHour, lMinute, lSecond;
            sscanf(pString, "%d-%d-%d %d:%d:%d", &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond);
            struct tm t = {0};
            t.tm_year = lYear - 1900;
            t.tm_mon = lMonth - 1;
            t.tm_mday = lDay;
            t.tm_hour = lHour;
            t.tm_min = lMinute;
            t.tm_sec = lSecond;
            t.tm_isdst = -1;
            return mktime(&t);
        }

        inline std::time_t timeFromStringDate(const char *time)
        {
            char s_month[5];
            int month, day, year;
            struct tm t = {0};
            static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

            sscanf(time, "%s %d %d", s_month, &day, &year);

            month = (int)(strstr(month_names, s_month)-month_names)/3;

            t.tm_mon = month;
            t.tm_mday = day;
            t.tm_year = year - 1900;
            t.tm_isdst = -1;

            return mktime(&t);
        }

        inline long long secondsSinceEpoch()
        {
            return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
        }
    }
}

#endif
<|endoftext|>