try
  {
    filter->Update();
  }
  catch(mitk::Exception& e)
  {
    MITK_ERROR << "exception caught: " << e.GetDescription();
    return nullptr;
  }

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

The Medical Imaging Interaction Toolkit (MITK)

All rights reserved.

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

#include "QmitkSurfaceToImageWidget.h"

#include <mitkException.h>
#include <mitkExceptionMacro.h>
#include <mitkProgressBar.h>
#include <mitkProperties.h>
#include <mitkIDataStorageService.h>
#include <mitkSurfaceStampImageFilter.h>

#include <berryPlatform.h>

#include <qmessagebox.h>

static const char* const HelpText = "Select a patient image and a surface";

QmitkSurfaceToImageWidget::QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent)
  : QmitkSegmentationUtilityWidget(timeNavigationController, parent)
{
  m_Controls.setupUi(this);

  m_Controls.m_DataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImagePredicate);
  m_Controls.m_DataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SurfacePredicate);
  m_Controls.m_DataSelectionWidget->SetHelpText(HelpText);

  mitk::DataStorage::Pointer ds = m_Controls.m_DataSelectionWidget->GetDataStorage();
  m_Controls.m_LabelSetWidget->SetDataStorage(ds);
  m_Controls.m_LabelSetWidget->setEnabled(true);

  m_Controls.m_SurfaceStampWidget->SetDataStorage(ds);

  this->EnableButtons(false);

  m_Controls.m_chkMakeOutputBinary->setChecked(true);

  connect (m_Controls.btnSurface2Image, SIGNAL(pressed()), this, SLOT(OnSurface2ImagePressed()));
  connect(m_Controls.m_DataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)),
    this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*)));
  connect (m_Controls.m_chkMakeOutputBinary, SIGNAL(toggled(bool)), this, SLOT(OnMakeOutputBinaryChanged(bool)));

  if( m_Controls.m_DataSelectionWidget->GetSelection(0).IsNotNull() &&
    m_Controls.m_DataSelectionWidget->GetSelection(1).IsNotNull() )
  {
    this->OnSelectionChanged( 0, m_Controls.m_DataSelectionWidget->GetSelection(0));
  }
}

QmitkSurfaceToImageWidget::~QmitkSurfaceToImageWidget()
{
}

void QmitkSurfaceToImageWidget::EnableButtons(bool enable)
{
  m_Controls.btnSurface2Image->setEnabled(enable);
  m_Controls.m_chkMakeOutputBinary->setEnabled(enable);
  m_Controls.m_chkOverwriteBackground->setEnabled(enable && !m_Controls.m_chkMakeOutputBinary->isChecked());
  m_Controls.m_leForegroundValue->setEnabled(enable && !m_Controls.m_chkMakeOutputBinary->isChecked());
  m_Controls.m_leBackgroundValue->setEnabled(enable && !m_Controls.m_chkMakeOutputBinary->isChecked());
}

void QmitkSurfaceToImageWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*)
{
  mitk::DataNode::Pointer imageNode = m_Controls.m_DataSelectionWidget->GetSelection(0);
  mitk::DataNode::Pointer surfaceNode = m_Controls.m_DataSelectionWidget->GetSelection(1);

  if (imageNode.IsNull() || surfaceNode.IsNull() )
  {
    m_Controls.m_DataSelectionWidget->SetHelpText(HelpText);
    this->EnableButtons(false);
  }
  else
  {
    mitk::Image::Pointer image = dynamic_cast<mitk::Image*>( m_Controls.m_DataSelectionWidget->GetSelection(0)->GetData() );
    mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*>( m_Controls.m_DataSelectionWidget->GetSelection(1)->GetData() );
    if( image->GetTimeSteps() != surface->GetTimeSteps() )
    {
      m_Controls.m_DataSelectionWidget->SetHelpText("Image and surface are of different size");
      this->EnableButtons(false);
    }
    else
    {
      m_Controls.m_DataSelectionWidget->SetHelpText("");
      this->EnableButtons();
    }
  }
}

void QmitkSurfaceToImageWidget::OnSurface2ImagePressed()
{
  this->EnableButtons(false);

  mitk::Image::Pointer image = dynamic_cast<mitk::Image*>( m_Controls.m_DataSelectionWidget->GetSelection(0)->GetData() );
  mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface*>( m_Controls.m_DataSelectionWidget->GetSelection(1)->GetData() );

  if( image.IsNull() || surface.IsNull())
  {
    MITK_ERROR << "Selection does not contain an image and/or a surface";
    QMessageBox::information( this, "Surface To Image", "Selection does not contain an image and/or a surface", QMessageBox::Ok );
    this->EnableButtons();
    return;
  }

  mitk::Image::Pointer resultImage(nullptr);
  resultImage = this->ConvertSurfaceToImage( image, surface );

  if( resultImage.IsNull() )
  {
    QMessageBox::information( this, "Surface to Image", "Could not stamp surface.\n See error log for details.", QMessageBox::Ok );
    this->EnableButtons();
    return;
  }

  //create name for result node
  std::string nameOfResultImage = m_Controls.m_DataSelectionWidget->GetSelection(0)->GetName();
  nameOfResultImage.append("_");
  nameOfResultImage.append(m_Controls.m_DataSelectionWidget->GetSelection(1)->GetName());

  //create data node and add to data storage
  mitk::DataNode::Pointer resultNode = mitk::DataNode::New();
  resultNode->SetData( resultImage );
  resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) );
  resultNode->SetProperty("binary", mitk::BoolProperty::New(m_Controls.m_chkMakeOutputBinary->isChecked()) );

  m_Controls.m_DataSelectionWidget->GetDataStorage()->Add(resultNode, m_Controls.m_DataSelectionWidget->GetSelection(0));

  this->EnableButtons();
}

mitk::Image::Pointer QmitkSurfaceToImageWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface )
{
  mitk::SurfaceStampImageFilter::Pointer filter = mitk::SurfaceStampImageFilter::New();
  filter->SetInput(image);
  filter->SetSurface(surface);
  filter->SetMakeOutputBinary(m_Controls.m_chkMakeOutputBinary->isChecked());
  filter->SetOverwriteBackground(m_Controls.m_chkOverwriteBackground->isChecked());
  filter->SetForegroundValue(m_Controls.m_leForegroundValue->text().toFloat());
  filter->SetBackgroundValue(m_Controls.m_leBackgroundValue->text().toFloat());

  mitk::Image::Pointer resultImage = filter->GetOutput();

  return resultImage;
}

void QmitkSurfaceToImageWidget::OnMakeOutputBinaryChanged(bool value)
{
  m_Controls.m_chkOverwriteBackground->setEnabled(!value);
  m_Controls.m_leForegroundValue->setEnabled(!value);
  m_Controls.m_leBackgroundValue->setEnabled(!value);
}


try
      {
         CommonTime ct;
         return ct.set( ( MJD_JDAY + UNIX_MJD + ts.tv_sec / SEC_PER_DAY ),
                        ( ts.tv_sec % SEC_PER_DAY ),
                        ( static_cast<double>( ts.tv_nsec ) * 1e-9 ),
                        timeSystem );
      }
      catch (InvalidParameter& ip)
      {
         InvalidRequest ir(ip);
         GPSTK_THROW(ip);
      }

//  This file is part of GPSTk, the GPS Toolkit.
//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin.

//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin, under contract to an agency or agencies
//  within the U.S. Department of Defense. The U.S. Government retains all
//  rights to use, duplicate, distribute, disclose, or release this software.
//  Pursuant to DoD Directive 523024
//  DISTRIBUTION STATEMENT A: This software has been approved for public
//                            release, distribution is unlimited.

/// @file PosixTime.cpp

#include "PosixTime.hpp"
#include "TimeConstants.hpp"

namespace gpstk
{
   PosixTime& PosixTime::operator=( const PosixTime& right )
   {
      ts.tv_sec  = right.ts.tv_sec ;
      ts.tv_nsec = right.ts.tv_nsec;
      timeSystem = right.timeSystem;
      return *this;
   }

   CommonTime PosixTime::convertToCommonTime() const
   {

   }

   void PosixTime::convertFromCommonTime( const CommonTime& ct )
   {
         /// This is the earliest CommonTime for which PosixTimes are valid.
      static const CommonTime MIN_CT = PosixTime(0, 0, TimeSystem::Any);
         /// This is the latest CommonTime for which PosixTimes are valid.
      static const CommonTime MAX_CT = PosixTime(2147483647, 999999,
                                                 TimeSystem::Any);

      if ( ct < MIN_CT || ct > MAX_CT )
      {
         InvalidRequest ir("Unable to convert given CommonTime to PosixTime.");
         GPSTK_THROW(ir);
      }

      long jday, sod;
      double fsod;
      ct.get( jday, sod, fsod, timeSystem );

      ts.tv_sec = (jday - MJD_JDAY - UNIX_MJD) * SEC_PER_DAY + sod;

         // round to the nearest nanosecond
      ts.tv_nsec = static_cast<time_t>( fsod * 1e9 + 0.5 ) ;

      if (ts.tv_nsec >= 1000000000)
      {
         ts.tv_nsec -= 1000000000;
         ++ts.tv_sec;
      }
   }

   std::string PosixTime::printf( const std::string& fmt ) const
   {
      try
      {
         using gpstk::StringUtils::formattedPrint;
         std::string rv( fmt );

         rv = formattedPrint(rv, getFormatPrefixInt() + "W",
                             "Wlu", ts.tv_sec);
         rv = formattedPrint(rv, getFormatPrefixInt() + "N",
                             "Nlu", ts.tv_nsec);
         rv = formattedPrint(rv, getFormatPrefixInt() + "P",
                             "Ps", StringUtils::asString(timeSystem).c_str() );
         return rv;
      }
      catch( gpstk::StringUtils::StringException& se )
      {
         GPSTK_RETHROW( se );
      }
   }

   std::string PosixTime::printError( const std::string& fmt ) const
   {
      try
      {
         using gpstk::StringUtils::formattedPrint;
         std::string rv( fmt );

         rv = formattedPrint(rv, getFormatPrefixInt() + "W",
                             "Ws", getError().c_str());
         rv = formattedPrint(rv, getFormatPrefixInt() + "N",
                             "Ns", getError().c_str());
         rv = formattedPrint( rv, getFormatPrefixInt() + "P",
                              "Ps", getError().c_str());
         return rv;
      }
      catch( gpstk::StringUtils::StringException& se )
      {
         GPSTK_RETHROW( se );
      }
   }

   bool PosixTime::setFromInfo( const IdToValue& info )
   {
      using namespace gpstk::StringUtils;

      for( IdToValue::const_iterator i = info.begin(); i != info.end(); i++ )
      {
         switch( i->first )
         {
            case 'W':
               ts.tv_sec = asInt( i->second );
               break;

            case 'N':
               ts.tv_nsec = asInt( i->second );
               break;

            case 'P':
               timeSystem = gpstk::StringUtils::asTimeSystem(i->second);
               break;

            default:
               break;
         };
      }

      return true;
   }

   bool PosixTime::isValid() const
   {
      PosixTime temp;
      temp.convertFromCommonTime( convertToCommonTime() );
      if( *this == temp )
      {
         return true;
      }
      return false;
   }

   void PosixTime::reset()
   {
      ts.tv_sec = ts.tv_nsec = 0;
      timeSystem = TimeSystem::Unknown;
   }

   bool PosixTime::operator==( const PosixTime& right ) const
   {
         /// Any (wildcard) type exception allowed, otherwise must be
         /// same time systems
      if ((timeSystem != TimeSystem::Any &&
           right.timeSystem != TimeSystem::Any) &&
          timeSystem != right.timeSystem)
         return false;

      if( ts.tv_sec == right.ts.tv_sec  &&
          abs(ts.tv_nsec - right.ts.tv_nsec) < CommonTime::eps )
      {
         return true;
      }
      return false;
   }

   bool PosixTime::operator!=( const PosixTime& right ) const
   {
      return ( !operator==( right ) );
   }

   bool PosixTime::operator<( const PosixTime& right ) const
   {
         /// Any (wildcard) type exception allowed, otherwise must be
         /// same time systems
      if ((timeSystem != TimeSystem::Any &&
           right.timeSystem != TimeSystem::Any) &&
          timeSystem != right.timeSystem)
      {
         gpstk::InvalidRequest ir("CommonTime objects not in same time system,"
                                  " cannot be compared");
         GPSTK_THROW(ir);
      }

      if( ts.tv_sec  <  right.ts.tv_sec )
      {
         return true;
      }
      if( ts.tv_sec  == right.ts.tv_sec  &&
          ts.tv_nsec <  right.ts.tv_nsec   )
      {
         return true;
      }
      return false;
   }

   bool PosixTime::operator>( const PosixTime& right ) const
   {
      return ( !operator<=( right ) );
   }

   bool PosixTime::operator<=( const PosixTime& right ) const
   {
      return ( operator<( right ) ||
               operator==( right ) );
   }

   bool PosixTime::operator>=( const PosixTime& right ) const
   {
      return ( !operator<( right ) );
   }

} // namespace


try {
    auto link = mavconn::MAVConnInterface::open_url(this->url);
    link->message_received_cb =
      std::bind(&MAVConnEndpoint::recv_message, shared_from_this(), _1, _2);
    this->link = link;
  } catch (mavconn::DeviceError & ex) {
    return {false, ex.what()};
  }

/*
 *
 */
/**
 * @brief Mavros Router class
 * @file mavros_router.cpp
 * @author Vladimir Ermakov <example@nnthink.com>
 */

#include <memory>
#include <vector>
#include <string>
#include <set>
#include <utility>

#include "mavros/mavros_router.hpp"
#include "rcpputils/asserts.hpp"

using namespace mavros::router;  // NOLINT
using rclcpp::QoS;

using unique_lock = std::unique_lock<std::shared_timed_mutex>;
using shared_lock = std::shared_lock<std::shared_timed_mutex>;

std::atomic<id_t> Router::id_counter {1000};

static inline uint8_t get_msg_byte(const mavlink_message_t * msg, uint8_t offset)
{
  return _MAV_PAYLOAD(msg)[offset];
}

void Router::route_message(
  Endpoint::SharedPtr src, const mavlink_message_t * msg,
  const Framing framing)
{
  shared_lock lock(mu);
  this->stat_msg_routed++;

  // find message destination target
  addr_t target_addr = 0;
  auto msg_entry = ::mavlink::mavlink_get_msg_entry(msg->msgid);
  if (msg_entry) {
    if (msg_entry->flags & MAV_MSG_ENTRY_FLAG_HAVE_TARGET_SYSTEM) {
      target_addr |= get_msg_byte(msg, msg_entry->target_system_ofs) << 8;
    }
    if (msg_entry->flags & MAV_MSG_ENTRY_FLAG_HAVE_TARGET_COMPONENT) {
      target_addr |= get_msg_byte(msg, msg_entry->target_component_ofs);
    }
  }

  size_t sent_cnt = 0, retry_cnt = 0;
retry:
  for (auto & kv : this->endpoints) {
    auto & dest = kv.second;

    if (src->id == dest->id) {
      continue;     // do not echo message
    }
    if (src->link_type == dest->link_type) {
      continue;     // drop messages between same type FCU/GCS/UAS
    }

    // NOTE(vooon): current router do not allow to speak drone-to-drone.
    //              if it is needed perhaps better to add mavlink-router in front of mavros-router.

    bool has_target = dest->remote_addrs.find(target_addr) != dest->remote_addrs.end();

    if (has_target) {
      dest->send_message(msg, framing, src->id);
      sent_cnt++;
    }
  }

  // if message haven't been sent retry broadcast it
  if (sent_cnt == 0 && retry_cnt < 2) {
    target_addr = 0;
    retry_cnt++;
    goto retry;
  }

  // update stats
  this->stat_msg_sent.fetch_add(sent_cnt);
  if (sent_cnt == 0) {
    this->stat_msg_dropped++;

    auto lg = get_logger();
    auto clock = get_clock();

    RCLCPP_WARN_THROTTLE(
      lg,
      *clock, 10000, "Message dropped: msgid: %d, source: %d.%d, target: %d.%d", msg->msgid,
      msg->sysid, msg->compid, target_addr >> 8,
      target_addr & 0xff);
  }
}

void Router::add_endpoint(
  const mavros_msgs::srv::EndpointAdd::Request::SharedPtr request,
  mavros_msgs::srv::EndpointAdd::Response::SharedPtr response)
{
  unique_lock lock(mu);
  auto lg = get_logger();

  RCLCPP_INFO(
    lg, "Requested to add endpoint: type: %d, url: %s", request->type,
    request->url.c_str());

  if (request->type > mavros_msgs::srv::EndpointAdd::Request::TYPE_UAS) {
    RCLCPP_ERROR(lg, "Unknown endpoint type");
    response->successful = false;
    response->reason = "unknown link type";
    return;
  }

  id_t id = id_counter.fetch_add(1);

  Endpoint::SharedPtr ep;
  if (request->type == mavros_msgs::srv::EndpointAdd::Request::TYPE_UAS) {
    ep = std::make_shared<ROSEndpoint>();
  } else {
    ep = std::make_shared<MAVConnEndpoint>();
  }

  // NOTE(vooon): has type std::shared_ptr<rclcpp::Node>
  auto shared_this = shared_from_this();

  ep->parent = std::static_pointer_cast<Router>(shared_this);
  ep->id = id;
  ep->link_type = static_cast<Endpoint::Type>(request->type);
  ep->url = request->url;

  this->endpoints[id] = ep;
  this->diagnostic_updater.add(ep->diag_name(), std::bind(&Endpoint::diag_run, ep, _1));
  RCLCPP_INFO(lg, "Endpoint link[%d] created", id);

  auto result = ep->open();
  if (result.first) {
    RCLCPP_INFO(lg, "link[%d] opened successfully", id);
  } else {
    RCLCPP_ERROR(lg, "link[%d] open failed: %s", id, result.second.c_str());
  }

  response->successful = result.first;
  response->reason = result.second;
  response->id = id;
}

void Router::del_endpoint(
  const mavros_msgs::srv::EndpointDel::Request::SharedPtr request,
  mavros_msgs::srv::EndpointDel::Response::SharedPtr response)
{
  unique_lock lock(mu);
  auto lg = get_logger();

  if (request->id != 0) {
    RCLCPP_INFO(lg, "Requested to del endpoint id: %d", request->id);
    auto it = this->endpoints.find(request->id);
    if (it != this->endpoints.end() ) {
      it->second->close();
      this->diagnostic_updater.removeByName(it->second->diag_name());
      this->endpoints.erase(it);
      response->successful = true;
    }
    return;
  }

  RCLCPP_INFO(
    lg, "Requested to del endpoint type: %d url: %s", request->type,
    request->url.c_str());
  for (auto it = this->endpoints.cbegin(); it != this->endpoints.cend(); it++) {
    if (it->second->url == request->url &&
      it->second->link_type == static_cast<Endpoint::Type>( request->type))
    {
      it->second->close();
      this->diagnostic_updater.removeByName(it->second->diag_name());
      this->endpoints.erase(it);
      response->successful = true;
      return;
    }
  }
}

rcl_interfaces::msg::SetParametersResult Router::on_set_parameters_cb(
  const std::vector<rclcpp::Parameter> & parameters)
{
  auto lg = get_logger();
  rcl_interfaces::msg::SetParametersResult result{};

  RCLCPP_DEBUG(lg, "params callback");

  using Type = Endpoint::Type;

  auto get_existing_set = [this](Type type) -> std::set<std::string> {
      shared_lock lock(this->mu);

      std::set<std::string> ret;

      for (const auto & kv : this->endpoints) {
        if (kv.second->link_type != type) {
          continue;
        }

        ret.emplace(kv.second->url);
      }

      return ret;
    };

  auto update_endpoints = [&, this](const rclcpp::Parameter & parameter, Type type) {
      RCLCPP_DEBUG(lg, "Processing urls parameter: %s", parameter.get_name().c_str());

      auto urls = parameter.as_string_array();
      std::set<std::string> urls_set(urls.begin(), urls.end());
      auto existing_set = get_existing_set(type);

      std::set<std::string> to_add{}, to_del{};
      std::set_difference(
        urls_set.begin(), urls_set.end(), existing_set.begin(),
        existing_set.end(), std::inserter(to_add, to_add.begin()));
      std::set_difference(
        existing_set.begin(), existing_set.end(), urls_set.begin(),
        urls_set.end(), std::inserter(to_del, to_del.begin()));

      for (auto url : to_add) {
        auto req = std::make_shared<mavros_msgs::srv::EndpointAdd::Request>();
        auto resp = std::make_shared<mavros_msgs::srv::EndpointAdd::Response>();

        req->type = utils::enum_value(type);
        req->url = url;

        this->add_endpoint(req, resp);
      }

      for (auto url : to_del) {
        auto req = std::make_shared<mavros_msgs::srv::EndpointDel::Request>();
        auto resp = std::make_shared<mavros_msgs::srv::EndpointDel::Response>();

        req->type = utils::enum_value(type);
        req->url = url;

        this->del_endpoint(req, resp);
      }
    };

  result.successful = true;
  for (const auto & parameter : parameters) {
    const auto name = parameter.get_name();
    if (name == "fcu_urls") {
      update_endpoints(parameter, Type::fcu);
    } else if (name == "gcs_urls") {
      update_endpoints(parameter, Type::gcs);
    } else if (name == "uas_urls") {
      update_endpoints(parameter, Type::uas);
    } else {
      result.successful = false;
      result.reason = "unknown parameter";
    }
  }

  return result;
}

void Router::periodic_reconnect_endpoints()
{
  shared_lock lock(mu);
  auto lg = get_logger();

  RCLCPP_DEBUG(lg, "start reconnecting...");

  for (auto & kv : this->endpoints) {
    auto & p = kv.second;

    if (p->is_open()) {
      continue;
    }

    RCLCPP_INFO(lg, "link[%d] trying to reconnect...", p->id);
    auto result = p->open();

    if (result.first) {
      RCLCPP_INFO(lg, "link[%d] reconnected", p->id);
    } else {
      RCLCPP_ERROR(lg, "link[%d] reconnect failed: %s", p->id, result.second.c_str());
    }
  }
}

void Router::periodic_clear_stale_remote_addrs()
{
  unique_lock lock(mu);
  auto lg = get_logger();

  RCLCPP_DEBUG(lg, "clear stale remotes");
  for (auto & kv : this->endpoints) {
    auto & p = kv.second;

    // Step 1: remove any stale addrs that still there
    //         (hadn't been removed by Endpoint::recv_message())
    for (auto addr : p->stale_addrs) {
      if (addr != 0) {
        p->remote_addrs.erase(addr);
        RCLCPP_INFO(
          lg, "link[%d] removed stale remote address %d.%d", p->id, addr >> 8,
          addr & 0xff);
      }
    }

    // Step 2: re-initiate stale_addrs
    p->stale_addrs.clear();
    p->stale_addrs.insert(p->remote_addrs.begin(), p->remote_addrs.end());
  }
}

void Router::diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat)
{
  auto endpoints_len = [this]() -> auto {
      shared_lock lock(this->mu);
      return this->endpoints.size();
    } ();

  stat.addf("Endpoints", "%zu", endpoints_len);
  stat.addf("Messages routed", "%zu", stat_msg_routed.load());
  stat.addf("Messages sent", "%zu", stat_msg_sent.load());
  stat.addf("Messages dropped", "%zu", stat_msg_dropped.load());

  if (endpoints_len < 2) {
    stat.summary(2, "not enough endpoints");
  } else {
    stat.summary(0, "ok");
  }
}

void Endpoint::recv_message(const mavlink_message_t * msg, const Framing framing)
{
  rcpputils::assert_true(msg, "msg not nullptr");
  // rcpputils::assert_true(this->parent, "parent not nullptr");

  const addr_t sysid_addr = msg->sysid << 8;
  const addr_t sysid_compid_addr = (msg->sysid << 8) | msg->compid;

  // save source addr to remote_addrs
  auto sp = this->remote_addrs.emplace(sysid_addr);
  auto scp = this->remote_addrs.emplace(sysid_compid_addr);

  // and delete it from stale_addrs
  this->stale_addrs.erase(sysid_addr);
  this->stale_addrs.erase(sysid_compid_addr);

  auto & nh = this->parent;
  if (sp.second || scp.second) {
    RCLCPP_INFO(
      nh->get_logger(), "link[%d] detected remote address %d.%d", this->id, msg->sysid,
      msg->compid);
  }

  nh->route_message(shared_from_this(), msg, framing);
}

std::string Endpoint::diag_name()
{
  return utils::format("endpoint %d: %s", this->id, this->url.c_str());
}

bool MAVConnEndpoint::is_open()
{
  if (!this->link) {
    return false;
  }

  return this->link->is_open();
}

std::pair<bool, std::string> MAVConnEndpoint::open()
{

  // not necessary because router would not serialize mavlink::Message
  // but that is a good default
  this->link->set_protocol_version(mavconn::Protocol::V20);

  return {true, ""};
}

void MAVConnEndpoint::close()
{
  if (!this->link) {
    return;
  }

  this->link->close();
  this->link.reset();
}

void MAVConnEndpoint::send_message(
  const mavlink_message_t * msg, const Framing framing,
  id_t src_id [[maybe_unused]])
{
  (void)framing;

  if (!this->link) {
    return;
  }

  this->link->send_message_ignore_drop(msg);
}

void MAVConnEndpoint::diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat)
{
  if (!this->link) {
    stat.summary(2, "closed");
    return;
  }

  auto mav_status = this->link->get_status();
  auto iostat = this->link->get_iostat();

  stat.addf("Received packets", "%u", mav_status.packet_rx_success_count);
  stat.addf("Dropped packets", "%u", mav_status.packet_rx_drop_count);
  stat.addf("Buffer overruns", "%u", mav_status.buffer_overrun);
  stat.addf("Parse errors", "%u", mav_status.parse_error);
  stat.addf("Rx sequence number", "%u", mav_status.current_rx_seq);
  stat.addf("Tx sequence number", "%u", mav_status.current_tx_seq);

  stat.addf("Rx total bytes", "%u", iostat.rx_total_bytes);
  stat.addf("Tx total bytes", "%u", iostat.tx_total_bytes);
  stat.addf("Rx speed", "%f", iostat.rx_speed);
  stat.addf("Tx speed", "%f", iostat.tx_speed);

  stat.addf("Remotes count", "%zu", this->remote_addrs.size());
  size_t idx = 0;
  for (auto addr : this->remote_addrs) {
    stat.addf(utils::format("Remote [%d]", idx++), "%d.%d", addr >> 8, addr & 0xff);
  }

  if (mav_status.packet_rx_drop_count > stat_last_drop_count) {
    stat.summaryf(
      1, "%d packeges dropped since last report",
      mav_status.packet_rx_drop_count - stat_last_drop_count);
  } else {
    stat.summary(0, "ok");
  }

  stat_last_drop_count = mav_status.packet_rx_drop_count;
}

bool ROSEndpoint::is_open()
{
  return this->source && this->sink;
}

std::pair<bool, std::string> ROSEndpoint::open()
{
  auto & nh = this->parent;
  if (!nh) {
    return {false, "parent not set"};
  }

  try {
    auto qos = QoS(
      1000).best_effort().durability_volatile();
    this->source =
      nh->create_publisher<mavros_msgs::msg::Mavlink>(
      utils::format(
        "%s/%s", this->url.c_str(),
        "mavlink_source"), qos);
    this->sink = nh->create_subscription<mavros_msgs::msg::Mavlink>(
      utils::format("%s/%s", this->url.c_str(), "mavlink_sink"), qos,
      std::bind(&ROSEndpoint::ros_recv_message, this, _1));
  } catch (rclcpp::exceptions::InvalidTopicNameError & ex) {
    return {false, ex.what()};
  }

  return {true, ""};
}

void ROSEndpoint::close()
{
  this->source.reset();
  this->sink.reset();
}

void ROSEndpoint::send_message(const mavlink_message_t * msg, const Framing framing, id_t src_id)
{
  rcpputils::assert_true(msg, "msg not null");

  auto rmsg = mavros_msgs::msg::Mavlink();
  auto ok = mavros_msgs::mavlink::convert(*msg, rmsg, utils::enum_value(framing));

  // don't fail if endpoint closed
  if (!this->source) {
    return;
  }

  rmsg.header.stamp = this->parent->now();
  rmsg.header.frame_id = utils::format("ep:%d", src_id);

  if (ok) {
    this->source->publish(rmsg);
  } else if (auto & nh = this->parent) {
    RCLCPP_ERROR(nh->get_logger(), "message conversion error");
  }
}

void ROSEndpoint::ros_recv_message(const mavros_msgs::msg::Mavlink::SharedPtr rmsg)
{
  rcpputils::assert_true(!!rmsg, "rmsg not nullptr");

  mavlink::mavlink_message_t mmsg;

  auto ok = mavros_msgs::mavlink::convert(*rmsg, mmsg);
  auto framing = static_cast<Framing>(rmsg->framing_status);

  if (ok) {
    recv_message(&mmsg, framing);
  } else if (auto & nh = this->parent) {
    RCLCPP_ERROR(nh->get_logger(), "message conversion error");
  }
}

void ROSEndpoint::diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat)
{
  // TODO(vooon): make some diagnostics

  stat.addf("Remotes count", "%zu", this->remote_addrs.size());
  size_t idx = 0;
  for (auto addr : this->remote_addrs) {
    stat.addf(utils::format("Remote [%d]", idx++), "%d.%d", addr >> 8, addr & 0xff);
  }

  if (this->is_open()) {
    stat.summary(0, "ok");
  } else {
    stat.summary(2, "closed");
  }
}

#include <rclcpp_components/register_node_macro.hpp>  // NOLINT
RCLCPP_COMPONENTS_REGISTER_NODE(mavros::router::Router)


try {
		nclrEndian.reset(open(nclr));
		palette.reset(loadNCLR(*nclrEndian));

	} catch (Common::Exception &e) {
		e.add("Failed reading NCLR file");
		throw;
	}

/* xoreos - A reimplementation of BioWare's Aurora engine
 *
 * xoreos is the legal property of its developers, whose names
 * can be found in the AUTHORS file distributed with this source
 * distribution.
 *
 */

/** @file
 *  Loading Nitro CoLoR palette files.
 */

/* Based heavily on the NCLR reader found in the NDS file viewer
 * and editor Tinke by pleoNeX (<http://example.com>),
 *
 * Tinke in turn is based on the NCLR documentation by lowlines
 * (<http://example.com>).
 *
 * The original copyright note in Tinke reads as follows:
 *
 *
 */

#include <cstring>
#include <memory>

#include "src/common/util.h"
#include "src/common/strutil.h"
#include "src/common/readstream.h"
#include "src/common/error.h"

#include "src/graphics/images/nclr.h"

static const uint32_t kNCLRID = MKTAG('N', 'C', 'L', 'R');
static const uint32_t kPLTTID = MKTAG('P', 'L', 'T', 'T');

namespace Graphics {

const byte *NCLR::load(Common::SeekableReadStream &nclr) {
	std::unique_ptr<Common::SeekableSubReadStreamEndian> nclrEndian;
	std::unique_ptr<const byte[]> palette;

	return palette.release();
}

const byte *NCLR::loadNCLR(Common::SeekableSubReadStreamEndian &nclr) {
	readHeader(nclr);

	return readPalette(nclr);
}

void NCLR::readHeader(Common::SeekableSubReadStreamEndian &nclr) {
	const uint32_t tag = nclr.readUint32();
	if (tag != kNCLRID)
		throw Common::Exception("Invalid NCLR file (%s)", Common::debugTag(tag).c_str());

	const uint16_t bom = nclr.readUint16();
	if (bom != 0xFEFF)
		throw Common::Exception("Invalid BOM: %u", bom);

	const uint8_t versionMinor = nclr.readByte();
	const uint8_t versionMajor = nclr.readByte();
	if ((versionMajor != 1) || (versionMinor != 0))
		throw Common::Exception("Unsupported version %u.%u", versionMajor, versionMinor);

	const uint32_t fileSize = nclr.readUint32();
	if (fileSize > nclr.size())
		throw Common::Exception("Size too large (%u > %u)", fileSize, (uint)nclr.size());

	const uint16_t headerSize = nclr.readUint16();
	if (headerSize != 16)
		throw Common::Exception("Invalid header size (%u)", headerSize);

	const uint16_t sectionCount = nclr.readUint16();
	if ((sectionCount != 1) && (sectionCount != 2))
		throw Common::Exception("Invalid number of sections (%u)", sectionCount);
}

const byte *NCLR::readPalette(Common::SeekableSubReadStreamEndian &nclr) {
	const uint32_t tag = nclr.readUint32();
	if (tag != kPLTTID)
		throw Common::Exception("Invalid PLTT section (%s)", Common::debugTag(tag).c_str());

	const uint32_t size  = nclr.readUint32();

	const uint16_t depthValue = nclr.readUint16();
	if ((depthValue != 3) && (depthValue != 4))
		throw Common::Exception("Invalid palette depth %u", depthValue);

	const uint8_t depth = (depthValue == 3) ? 4 : 8;

	nclr.skip(6); // Unknown

	// Palette size. If not given or too big, calculate it from the section size
	uint32_t palSize = nclr.readUint32();
	if ((palSize == 0) || (palSize > size))
		palSize = size - 24;

	const uint32_t startOffset = nclr.readUint32() + 24;

	// Clamp the number of colors to the actual palette size
	const uint32_t colorCount = MIN<uint32_t>(1 << depth, palSize / 2) * 3;

	nclr.seek(startOffset);

	std::unique_ptr<byte[]> palette = std::make_unique<byte[]>(colorCount * 3);

	for (uint32_t i = 0; i < colorCount; i += 3) {
		const uint16_t color = nclr.readUint16();

		palette[i + 0] = ((color >> 10) & 0x1F) << 3;
		palette[i + 1] = ((color >>  5) & 0x1F) << 3;
		palette[i + 2] = ( color        & 0x1F) << 3;
	}

	// Make the rest of the palette pink, for high debug visibility
	static const byte kPink[3] = { 0xFF, 0x00, 0xFF };
	for (uint32_t i = colorCount; i < 768; i += sizeof(kPink))
		std::memcpy(palette.get() + i, kPink, sizeof(kPink));

	return palette.release();
}

} // End of namespace Graphics


try {
			// transparent conversion to 24-bit (any transparency table will be destroyed)
			src24 = FreeImage_ConvertTo24Bits(src);
			if(!src24) throw(1);
			// perform upsampling or downsampling
			dst = Engine.scale(src24, dst_width, dst_height);
			if(!dst) throw(1);
			// free and return
			FreeImage_Unload(src24);
		} catch(int) {
			if(src24) FreeImage_Unload(src24);
			if(dst) FreeImage_Unload(dst);
		}

// Upsampling / downsampling routine
// Design and implementation by

#include "Resize.h"

FIBITMAP * DLL_CALLCONV
FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) {
	FIBITMAP *dst = NULL;

	if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) {
		return NULL;
	}

	// select the filter
	CGenericFilter *pFilter = NULL;
	switch(filter) {
		case FILTER_BOX:
			pFilter = new(std::nothrow) CBoxFilter();
			break;
		case FILTER_BICUBIC:
			pFilter = new(std::nothrow) CBicubicFilter();
			break;
		case FILTER_BILINEAR:
			pFilter = new(std::nothrow) CBilinearFilter();
			break;
		case FILTER_BSPLINE:
			pFilter = new(std::nothrow) CBSplineFilter();
			break;
		case FILTER_CATMULLROM:
			pFilter = new(std::nothrow) CCatmullRomFilter();
			break;
		case FILTER_LANCZOS3:
			pFilter = new(std::nothrow) CLanczos3Filter();
			break;
	}

	if(!pFilter) {
		return NULL;
	}

	CResizeEngine Engine(pFilter);

	// perform upsampling or downsampling

	if((FreeImage_GetBPP(src) == 4) || (FreeImage_GetColorType(src) == FIC_PALETTE)) {
		// special case for 4-bit images or color map indexed images ...
		if(FreeImage_IsTransparent(src) == FALSE) {
			FIBITMAP *src24 = NULL;
			FIBITMAP *dst24 = NULL;
			try {
				// transparent conversion to 24-bit (any transparency table will be destroyed)
				src24 = FreeImage_ConvertTo24Bits(src);
				if(!src24) throw(1);
				// perform upsampling or downsampling
				dst24 = Engine.scale(src24, dst_width, dst_height);
				if(!dst24) throw(1);
				// color quantize to 8-bit
				dst = FreeImage_ColorQuantize(dst24, FIQ_NNQUANT);
				// free and return
				FreeImage_Unload(src24);
				FreeImage_Unload(dst24);
			} catch(int) {
				if(src24) FreeImage_Unload(src24);
				if(dst24) FreeImage_Unload(dst24);
			}
		} else {
			FIBITMAP *src32 = NULL;
			try {
				// transparent conversion to 32-bit (keep transparency)
				src32 = FreeImage_ConvertTo32Bits(src);
				if(!src32) throw(1);
				// perform upsampling or downsampling
				dst = Engine.scale(src32, dst_width, dst_height);
				if(!dst) throw(1);
				// free and return
				FreeImage_Unload(src32);
			} catch(int) {
				if(src32) FreeImage_Unload(src32);
				if(dst) FreeImage_Unload(dst);
			}
		}
	}
	else if((FreeImage_GetBPP(src) == 16) && (FreeImage_GetImageType(src) == FIT_BITMAP)) {
		// convert 16-bit RGB to 24-bit
		FIBITMAP *src24 = NULL;

	}
	else {
		dst = Engine.scale(src, dst_width, dst_height);
	}

	delete pFilter;

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);

	return dst;
}

FIBITMAP * DLL_CALLCONV
FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) {
	FIBITMAP *thumbnail = NULL;
	int new_width, new_height;

	if(!FreeImage_HasPixels(dib) || (max_pixel_size <= 0)) return NULL;

	int width	= FreeImage_GetWidth(dib);
	int height = FreeImage_GetHeight(dib);

	if(max_pixel_size == 0) max_pixel_size = 1;

	if((width < max_pixel_size) && (height < max_pixel_size)) {
		// image is smaller than the requested thumbnail
		return FreeImage_Clone(dib);
	}

	if(width > height) {
		new_width = max_pixel_size;
		// change image height with the same ratio
		double ratio = ((double)new_width / (double)width);
		new_height = (int)(height * ratio + 0.5);
		if(new_height == 0) new_height = 1;
	} else {
		new_height = max_pixel_size;
		// change image width with the same ratio
		double ratio = ((double)new_height / (double)height);
		new_width = (int)(width * ratio + 0.5);
		if(new_width == 0) new_width = 1;
	}

	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

	// perform downsampling using a bilinear interpolation

	switch(image_type) {
		case FIT_BITMAP:
		case FIT_UINT16:
		case FIT_RGB16:
		case FIT_RGBA16:
		case FIT_FLOAT:
		case FIT_RGBF:
		case FIT_RGBAF:
		{
			FREE_IMAGE_FILTER filter = FILTER_BILINEAR;
			thumbnail = FreeImage_Rescale(dib, new_width, new_height, filter);
		}
		break;

		case FIT_INT16:
		case FIT_UINT32:
		case FIT_INT32:
		case FIT_DOUBLE:
		case FIT_COMPLEX:
		default:
			// cannot rescale this kind of image
			thumbnail = NULL;
			break;
	}

	if((thumbnail != NULL) && (image_type != FIT_BITMAP) && convert) {
		// convert to a standard bitmap
		FIBITMAP *bitmap = NULL;
		switch(image_type) {
			case FIT_UINT16:
				bitmap = FreeImage_ConvertTo8Bits(thumbnail);
				break;
			case FIT_RGB16:
				bitmap = FreeImage_ConvertTo24Bits(thumbnail);
				break;
			case FIT_RGBA16:
				bitmap = FreeImage_ConvertTo32Bits(thumbnail);
				break;
			case FIT_FLOAT:
				bitmap = FreeImage_ConvertToStandardType(thumbnail, TRUE);
				break;
			case FIT_RGBF:
				bitmap = FreeImage_ToneMapping(thumbnail, FITMO_DRAGO03);
				break;
			case FIT_RGBAF:
				// no way to keep the transparency yet ...
				FIBITMAP *rgbf = FreeImage_ConvertToRGBF(thumbnail);
				bitmap = FreeImage_ToneMapping(rgbf, FITMO_DRAGO03);
				FreeImage_Unload(rgbf);
				break;
		}
		if(bitmap != NULL) {
			FreeImage_Unload(thumbnail);
			thumbnail = bitmap;
		}
	}

	// copy metadata from src to dst
	FreeImage_CloneMetadata(thumbnail, dib);

	return thumbnail;
}


try
        {
            simulation->run(nSteps);
        }
        catch (std::runtime_error e)
        {
            // Nothing to do here, score will be set to -1
        }

/*
 * All rights reserved.
 *
*/

/**
 * @file AppMixedCPG.cpp
 * @brief Using Brian's existing spine controller for a quadruped.
 * @author Dawn Hustig-Schultz, Brian Mirletz
 * @date August 2015
 * @version 1.0.0
 * $Id$
 */

#include "AppSpineControl.h"
#include "dev/btietz/JSONTests/tgCPGJSONLogger.h"

AppSpineControl::AppSpineControl(int argc, char** argv)
{
    bSetup = false;
    use_graphics = false;
    add_controller = true;
    add_blocks = false;
    add_hills = false;
    all_terrain = false;
    timestep_physics = 1.0f/1000.0f;
    timestep_graphics = 1.0f/60.0f;
    nEpisodes = 1;
    nSteps = 60000;
    nSegments = 7;
    nTypes = 3;

    startX = 0;
    startY = 20; //May need adjustment
    startZ = 0;
    startAngle = 0;

    suffix = "default";
    lowerPath = "default";

    handleOptions(argc, argv);
}

bool AppSpineControl::setup()
{
    // First create the world
    world = createWorld();

    // Second create the view
    if (use_graphics)
        view = createGraphicsView(world); // For visual experimenting on one tensegrity
    else
        view = createView(world);         // For running multiple episodes

    // Third create the simulation
    simulation = new tgSimulation(*view);

    // Fourth create the models with their controllers and add the models to the
    // simulation
    /// @todo add position and angle to configuration

    //Parameters for the structure:
    const int segments = 7;
    const int hips = 4;

    BigPuppySpineOnly* myModel = new BigPuppySpineOnly(segments, hips);

    // Fifth create the controllers, attach to model
    if (add_controller)
    {
        const int segmentSpan = 3; //Not sure what this will be for mine!
        const int numMuscles = 8; //This may be ok, but confirm.
        const int numParams = 2;
        const int segNumber = 0; // For learning results
        const double controlTime = .01;
        const double lowPhase = -1 * M_PI;
        const double highPhase = M_PI;
        const double lowAmplitude = 0.0;
        const double highAmplitude = 300.0;
        const double kt = 0.0; //May need to retune kt, kp, and kv
        const double kp = 1000.0;
        const double kv = 200.0;
        const bool def = true;

        // Overridden by def being true
        const double cl = 10.0;
        const double lf = 0.0;
        const double hf = 30.0;

        // Feedback parameters... may need to retune
        const double ffMin = -0.5;
        const double ffMax = 10.0;
        const double afMin = 0.0;
        const double afMax = 200.0;
        const double pfMin = -0.5;
        const double pfMax =  6.28;

	const double maxH = 30.0;
	const double minH = 1.0;

        JSONQuadFeedbackControl::Config control_config(segmentSpan,
                                                    numMuscles,
                                                    numMuscles,
                                                    numParams,
                                                    segNumber,
                                                    controlTime,
                                                    lowAmplitude,
                                                    highAmplitude,
                                                    lowPhase,
                                                    highPhase,
                                                    kt,
                                                    kp,
                                                    kv,
                                                    def,
                                                    cl,
                                                    lf,
                                                    hf,
                                                    ffMin,
                                                    ffMax,
                                                    afMin,
                                                    afMax,
                                                    pfMin,
                                                    pfMax,
						    maxH,
						    minH);
        /// @todo fix memory leak that occurs here
       JSONQuadFeedbackControl* const myControl =
        new JSONQuadFeedbackControl(control_config, suffix, lowerPath);

#if (0)
            tgCPGJSONLogger* const myLogger =
      new tgCPGJSONLogger("logs/CPGValues.txt");

    myControl->attach(myLogger);
#endif
        myModel->attach(myControl);
    }

    // Sixth add model & controller to simulation
    simulation->addModel(myModel);

    if (add_blocks)
    {
        tgModel* blockField = getBlocks();
        simulation->addObstacle(blockField);
    }

    bSetup = true;
    return bSetup;
}

void AppSpineControl::handleOptions(int argc, char **argv)
{
    // Declare the supported options.
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message")
        ("graphics,G", po::value<bool>(&use_graphics), "Test using graphical view")
        ("controller,c", po::value<bool>(&add_controller), "Attach the controller to the model.")
        ("blocks,b", po::value<bool>(&add_blocks)->implicit_value(false), "Add a block field as obstacles.")
        ("hills,H", po::value<bool>(&add_hills)->implicit_value(false), "Use hilly terrain.")
        ("all_terrain,A", po::value<bool>(&all_terrain)->implicit_value(false), "Alternate through terrain types. Only works with graphics off")
        ("phys_time,p", po::value<double>(), "Physics timestep value (Hz). Default=1000")
        ("graph_time,g", po::value<double>(), "Graphics timestep value a.k.a. render rate (Hz). Default = 60")
        ("episodes,e", po::value<int>(&nEpisodes), "Number of episodes to run. Default=1")
        ("steps,s", po::value<int>(&nSteps), "Number of steps per episode to run. Default=60K (60 seconds)")
        ("segments,S", po::value<int>(&nSegments), "Number of segments in the tensegrity spine. Default=6")
        ("start_x,x", po::value<double>(&startX), "X Coordinate of starting position for robot. Default = 0")
        ("start_y,y", po::value<double>(&startY), "Y Coordinate of starting position for robot. Default = 20")
        ("start_z,z", po::value<double>(&startZ), "Z Coordinate of starting position for robot. Default = 0")
        ("angle,a", po::value<double>(&startAngle), "Angle of starting rotation for robot. Degrees. Default = 0")
        ("goal_angle,B", po::value<double>(&goalAngle), "Angle of starting rotation for goal box. Degrees. Default = 0")
        ("learning_controller,l", po::value<std::string>(&suffix), "Which learned controller to write to or use. Default = default")
	("lower_path,P", po::value<std::string>(&lowerPath), "Which resources folder in which you want to store controllers. Default = default")
    ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);

    if (vm.count("help"))
    {
        std::cout << desc << "\n";
        exit(0);
    }

    po::notify(vm);

    if (vm.count("phys_time"))
    {
        timestep_physics = 1/vm["phys_time"].as<double>();
        std::cout << "Physics timestep set to: " << timestep_physics << " seconds.\n";
    }

    if (vm.count("graph_time"))
    {
        timestep_graphics = 1/vm["graph_time"].as<double>();
        std::cout << "Graphics timestep set to: " << timestep_graphics << " seconds.\n";
    }
}

const tgHillyGround::Config AppSpineControl::getHillyConfig()
{
    btVector3 eulerAngles = btVector3(0.0, 0.0, 0.0);
    btScalar friction = 0.5;
    btScalar restitution = 0.0;
    // Size doesn't affect hilly terrain
    btVector3 size = btVector3(0.0, 0.1, 0.0);
    btVector3 origin = btVector3(0.0, 0.0, 0.0);
    size_t nx = 100;
    size_t ny = 100;
    double margin = 0.5;
    double triangleSize = 4.0;
    double waveHeight = 2.0;
    double offset = 0.0;
    const tgHillyGround::Config hillGroundConfig(eulerAngles, friction, restitution,
                                    size, origin, nx, ny, margin, triangleSize,
                                    waveHeight, offset);
    return hillGroundConfig;
}

const tgBoxGround::Config AppSpineControl::getBoxConfig()
{
    const double yaw = 0.0;
    const double pitch = 0.0;
    const double roll = 0.0;
    const double friction = 0.5;
    const double restitution = 0.0;
    const btVector3 size(1000.0, 1.5, 1000.0);

    const tgBoxGround::Config groundConfig(btVector3(yaw, pitch, roll),
                                            friction,
                                            restitution,
                                            size    );

    return groundConfig;
}

tgModel* AppSpineControl::getBlocks()
{
    // Room to add a config
    tgBlockField* myObstacle = new tgBlockField();
    return myObstacle;
}

tgWorld* AppSpineControl::createWorld()
{
    const tgWorld::Config config(
        981 // gravity, cm/sec^2
    );

    tgBulletGround* ground;

    if (add_hills)
    {
        const tgHillyGround::Config hillGroundConfig = getHillyConfig();
        ground = new tgHillyGround(hillGroundConfig);
    }
    else
    {
        const tgBoxGround::Config groundConfig = getBoxConfig();
        ground = new tgBoxGround(groundConfig);
    }

    return new tgWorld(config, ground);
}

tgSimViewGraphics *AppSpineControl::createGraphicsView(tgWorld *world)
{
    return new tgSimViewGraphics(*world, timestep_physics, timestep_graphics);
}

tgSimView *AppSpineControl::createView(tgWorld *world)
{
    return new tgSimView(*world, timestep_physics, timestep_graphics);
}

bool AppSpineControl::run()
{
    if (!bSetup)
    {
        setup();
    }

    if (use_graphics)
    {
        // Run until the user stops
        simulation->run();
    }
    else
    {
        // or run for a specific number of steps
        simulate(simulation);
    }

    ///@todo consider app.cleanup()
   delete simulation;
   delete view;
   delete world;

    return true;
}

void AppSpineControl::simulate(tgSimulation *simulation)
{
    for (int i=0; i<nEpisodes; i++) {
        fprintf(stderr,"Episode %d\n", i);

        // Don't change the terrain before the last episode to avoid leaks
        if (all_terrain && i != nEpisodes - 1)
        {
            // Next run has Hills
            if (i % nTypes == 0)
            {

                const tgHillyGround::Config hillGroundConfig = getHillyConfig();
                tgBulletGround* ground = new tgHillyGround(hillGroundConfig);
                simulation->reset(ground);
            }
            // Flat
            else if (i % nTypes == 1)
            {
                const tgBoxGround::Config groundConfig = getBoxConfig();
                tgBulletGround* ground = new tgBoxGround(groundConfig);
                simulation->reset(ground);
            }
            // Flat with blocks
            else if (i % nTypes == 2)
            {
                simulation->reset();
                tgModel* obstacle = getBlocks();
                simulation->addObstacle(obstacle);
            }
        }
        // Avoid resetting twice on the last run
        else if (i != nEpisodes - 1)
        {
            simulation->reset();
        }

    }
}

/**
 * The entry point.
 * @param[in] argc the number of command-line arguments
 * @param[in] argv argv[0] is the executable name
 * @return 0
 */
int main(int argc, char** argv)
{
    std::cout << "AppSpineControl" << std::endl;
    AppSpineControl app (argc, argv);

    if (app.setup())
        app.run();

    //Teardown is handled by delete, so that should be automatic
    return 0;
}


try {
            m_modelList->openDirAndDiff();
        } catch ( const QString & /*str*/ ) {
            throw;
        } catch ( ... ) {
            throw QStringLiteral( "lib/libdiff2 crashed, memory may be corrupted. Please restart kdevelop." );
        }

/*

*/

#include "patchreview.h"

#include <QDir>
#include <QFileInfo>
#include <QStandardPaths>
#include <QTimer>
#include <QMimeDatabase>

#include <KActionCollection>
#include <KLocalizedString>
#include <KPluginFactory>
#include <KMessageBox>
#include <KIO/CopyJob>

#include <interfaces/idocument.h>
#include <interfaces/icore.h>
#include <interfaces/idocumentcontroller.h>
#include <interfaces/iuicontroller.h>
#include <interfaces/contextmenuextension.h>
#include <interfaces/context.h>
#include <interfaces/editorcontext.h>

#include <project/projectmodel.h>

#include <sublime/message.h>
#include <util/path.h>

#include <libkomparediff2/komparemodellist.h>
#include <libkomparediff2/kompare.h>
#include <libkomparediff2/diffsettings.h>

#include <KTextEditor/Document>
#include <KTextEditor/ModificationInterface>
#include <KTextEditor/MovingRange>
#include <KTextEditor/View>

///Whether arbitrary exceptions that occurred while diff-parsing within the library should be caught
#define CATCHLIBDIFF

/* Exclude this file from doublequote_chars check as krazy doesn't understand
   std::string*/
#include <sublime/controller.h>
#include <sublime/mainwindow.h>
#include <sublime/area.h>
#include <sublime/document.h>
#include <sublime/view.h>
#include <vcs/widgets/vcsdiffpatchsources.h>
#include "patchhighlighter.h"
#include "patchreviewtoolview.h"
#include "localpatchsource.h"
#include "debug.h"

using namespace KDevelop;

namespace
{
// Maximum number of files to open directly within a tab when the review is started
const int maximumFilesToOpenDirectly = 15;
}

void PatchReviewPlugin::seekHunk( bool forwards, const QUrl& fileName ) {
    try {
        qCDebug(PLUGIN_PATCHREVIEW) << forwards << fileName << fileName.isEmpty();
        if ( !m_modelList )
            throw "no model";

        for ( int a = 0; a < m_modelList->modelCount(); ++a ) {
            const Diff2::DiffModel* model = m_modelList->modelAt( a );
            if ( !model || !model->differences() )
                continue;

            QUrl file = urlForFileModel( model );

            if ( !fileName.isEmpty() && fileName != file )
                continue;

            IDocument* doc = ICore::self()->documentController()->documentForUrl( file );

            if ( doc && m_highlighters.contains( doc->url() ) && m_highlighters[doc->url()] ) {
                if ( doc->textDocument() ) {
                    const QList<KTextEditor::MovingRange*> ranges = m_highlighters[doc->url()]->ranges();

                    KTextEditor::View * v = doc->activeTextView();
                    if ( v ) {
                        int bestLine = -1;
                        KTextEditor::Cursor c = v->cursorPosition();
                        for (auto* range : ranges) {
                            const int line = range->start().line();

                            if ( forwards ) {
                                if ( line > c.line() && ( bestLine == -1 || line < bestLine ) )
                                    bestLine = line;
                            } else {
                                if ( line < c.line() && ( bestLine == -1 || line > bestLine ) )
                                    bestLine = line;
                            }
                        }
                        if ( bestLine != -1 ) {
                            v->setCursorPosition( KTextEditor::Cursor( bestLine, 0 ) );
                            return;
                        } else if(fileName.isEmpty()) {
                            int next = qBound(0, forwards ? a+1 : a-1, m_modelList->modelCount()-1);
                            if (next < maximumFilesToOpenDirectly) {
                                ICore::self()->documentController()->openDocument(urlForFileModel(m_modelList->modelAt(next)));
                            }
                        }
                    }
                }
            }
        }
    } catch ( const QString & str ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "seekHunk():" << str;
    } catch ( const char * str ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "seekHunk():" << str;
    }
    qCDebug(PLUGIN_PATCHREVIEW) << "no matching hunk found";
}

void PatchReviewPlugin::addHighlighting( const QUrl& highlightFile, IDocument* document ) {
    try {
        if ( !modelList() )
            throw "no model";

        for ( int a = 0; a < modelList()->modelCount(); ++a ) {
            Diff2::DiffModel* model = modelList()->modelAt( a );
            if ( !model )
                continue;

            QUrl file = urlForFileModel( model );

            if ( file != highlightFile )
                continue;

            qCDebug(PLUGIN_PATCHREVIEW) << "highlighting" << file.toDisplayString();

            IDocument* doc = document;
            if( !doc )
                doc = ICore::self()->documentController()->documentForUrl( file );

            qCDebug(PLUGIN_PATCHREVIEW) << "highlighting file" << file << "with doc" << doc;

            if ( !doc || !doc->textDocument() )
                continue;

            removeHighlighting( file );

            m_highlighters[file] = new PatchHighlighter(model, doc, this, (qobject_cast<LocalPatchSource*>(m_patch.data()) == nullptr));
        }
    } catch ( const QString & str ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "highlightFile():" << str;
    } catch ( const char * str ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "highlightFile():" << str;
    }
}

void PatchReviewPlugin::highlightPatch() {
    try {
        if ( !modelList() )
            throw "no model";

        for ( int a = 0; a < modelList()->modelCount(); ++a ) {
            const Diff2::DiffModel* model = modelList()->modelAt( a );
            if ( !model )
                continue;

            QUrl file = urlForFileModel( model );

            addHighlighting( file );
        }
    } catch ( const QString & str ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "highlightFile():" << str;
    } catch ( const char * str ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "highlightFile():" << str;
    }
}

void PatchReviewPlugin::removeHighlighting( const QUrl& file ) {
    if ( file.isEmpty() ) {
        ///Remove all highlighting
        qDeleteAll( m_highlighters );
        m_highlighters.clear();
    } else {
        HighlightMap::iterator it = m_highlighters.find( file );
        if ( it != m_highlighters.end() ) {
            delete *it;
            m_highlighters.erase( it );
        }
    }
}

void PatchReviewPlugin::notifyPatchChanged() {
    if (m_patch) {
        qCDebug(PLUGIN_PATCHREVIEW) << "notifying patch change: " << m_patch->file();
        m_updateKompareTimer->start();
    } else {
        m_updateKompareTimer->stop();
    }
}

void PatchReviewPlugin::forceUpdate() {
    if( m_patch ) {
        // don't trigger an update if we know the plugin cannot update itself
        auto* vcsPatch = qobject_cast<VCSDiffPatchSource*>(m_patch.data());
        if (!vcsPatch || vcsPatch->m_updater) {
            m_patch->update();
            notifyPatchChanged();
        }
    }
}

void PatchReviewPlugin::updateKompareModel() {
    if ( !m_patch ) {
        ///TODO: this method should be cleaned up, it can be called by the timer and
        ///      e.g. http://example.com shows how it could
        return;
    }

    qCDebug(PLUGIN_PATCHREVIEW) << "updating model";
    removeHighlighting();
    m_modelList.reset( nullptr );
    m_depth = 0;
    delete m_diffSettings;
    {
        IDocument* patchDoc = ICore::self()->documentController()->documentForUrl( m_patch->file() );
        if( patchDoc )
            patchDoc->reload();
    }

    QString patchFile;
    if( m_patch->file().isLocalFile() )
        patchFile = m_patch->file().toLocalFile();
    else if( m_patch->file().isValid() && !m_patch->file().isEmpty() ) {
        patchFile = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
        bool ret = KIO::copy(m_patch->file(), QUrl::fromLocalFile(patchFile), KIO::HideProgressInfo)->exec();
        if( !ret ) {
            qCWarning(PLUGIN_PATCHREVIEW) << "Problem while downloading: " << m_patch->file() << "to" << patchFile;
            patchFile.clear();
        }
    }

    if (!patchFile.isEmpty()) //only try to construct the model if we have a patch to load
    try {
        m_diffSettings = new DiffSettings( nullptr );
        m_kompareInfo.reset( new Kompare::Info() );
        m_kompareInfo->localDestination = patchFile;
        m_kompareInfo->localSource = m_patch->baseDir().toLocalFile();
        m_kompareInfo->depth = m_patch->depth();
        m_kompareInfo->applied = m_patch->isAlreadyApplied();

        m_modelList.reset( new Diff2::KompareModelList( m_diffSettings.data(), new QWidget, this ) );
        m_modelList->slotKompareInfo( m_kompareInfo.data() );

        for (m_depth = 0; m_depth < 10; ++m_depth) {
            bool allFound = true;
            for( int i = 0; i < m_modelList->modelCount(); i++ ) {
                if (!QFile::exists(urlForFileModel(m_modelList->modelAt(i)).toLocalFile())) {
                    allFound = false;
                }
            }
            if (allFound) {
                break; // found depth
            }
        }

        emit patchChanged();

        for( int i = 0; i < m_modelList->modelCount(); i++ ) {
            const Diff2::DiffModel* model = m_modelList->modelAt( i );
            for (auto* difference : *model->differences()) {
                difference->apply(m_patch->isAlreadyApplied());
            }
        }

        highlightPatch();

        return;
    } catch ( const QString & str ) {
        KMessageBox::error(nullptr, str, i18nc("@title:window", "Kompare Model Update"));
    } catch ( const char * str ) {
        KMessageBox::error(nullptr, QLatin1String(str), i18nc("@title:window", "Kompare Model Update"));
    }
    removeHighlighting();
    m_modelList.reset( nullptr );
    m_depth = 0;
    m_kompareInfo.reset( nullptr );
    delete m_diffSettings;

    emit patchChanged();
}

K_PLUGIN_FACTORY_WITH_JSON(KDevPatchReviewFactory, "kdevpatchreview.json",
                           registerPlugin<PatchReviewPlugin>();)

class PatchReviewToolViewFactory : public KDevelop::IToolViewFactory
{
public:
    explicit PatchReviewToolViewFactory( PatchReviewPlugin *plugin ) : m_plugin( plugin ) {}

    QWidget* create( QWidget *parent = nullptr ) override {
        return new PatchReviewToolView( parent, m_plugin );
    }

    Qt::DockWidgetArea defaultPosition() const override
    {
        return Qt::BottomDockWidgetArea;
    }

    QString id() const override {
        return QStringLiteral("org.kdevelop.PatchReview");
    }

private:
    PatchReviewPlugin *m_plugin;
};

PatchReviewPlugin::~PatchReviewPlugin()
{
    removeHighlighting();

    // Tweak to work around a crash on OS X; see http://example.com
    // modified tweak: use setPatch() and deleteLater in that method.
    setPatch(nullptr);
}

void PatchReviewPlugin::closeReview()
{
    if( m_patch ) {
        IDocument* patchDocument = ICore::self()->documentController()->documentForUrl( m_patch->file() );
        if (patchDocument) {
            // Revert modifications to the text document which we've done in updateReview
            patchDocument->setPrettyName( QString() );
            patchDocument->textDocument()->setReadWrite( true );
            auto* modif = qobject_cast<KTextEditor::ModificationInterface*>(patchDocument->textDocument());
            modif->setModifiedOnDiskWarning( true );
        }

        removeHighlighting();
        m_modelList.reset( nullptr );
        m_depth = 0;

        if (!qobject_cast<LocalPatchSource*>(m_patch.data())) {
            // make sure "show" button still openes the file dialog to open a custom patch file
            setPatch( new LocalPatchSource );
        } else
            emit patchChanged();

        auto oldArea = ICore::self()->uiController()->activeArea();
        if (oldArea->objectName() == QLatin1String("review")) {
            if (ICore::self()->documentController()->saveAllDocumentsForWindow(ICore::self()->uiController()->activeMainWindow(),
                                                                               IDocument::Default, true))
            {
                ICore::self()->uiController()->switchToArea(m_lastArea.isEmpty() ? QStringLiteral("code") : m_lastArea,
                                                            KDevelop::IUiController::ThisWindow);
                if (oldArea->workingSetPersistent()) {
                    ICore::self()->uiController()->activeArea()->setWorkingSet(oldArea->workingSet(), true, oldArea);
                }
            }
        }
    }
}

void PatchReviewPlugin::cancelReview() {
    if( m_patch ) {
        m_patch->cancelReview();
        closeReview();
    }
}

void PatchReviewPlugin::finishReview(const QList<QUrl>& selection)
{
    if( m_patch && m_patch->finishReview( selection ) ) {
        closeReview();
    }
}

void PatchReviewPlugin::startReview( IPatchSource* patch, IPatchReview::ReviewMode mode ) {
    Q_UNUSED( mode );
    emit startingNewReview();
    setPatch( patch );
    QMetaObject::invokeMethod(this, &PatchReviewPlugin::updateReview, Qt::QueuedConnection);
}

void PatchReviewPlugin::switchToEmptyReviewArea()
{
    const auto allAreas = ICore::self()->uiController()->allAreas();
    for (Sublime::Area* area : allAreas) {
        if (area->objectName() == QLatin1String("review")) {
            area->setWorkingSet(QString(), false);
        }
    }

    QString areaName = ICore::self()->uiController()->activeArea()->objectName();
    if (areaName != QLatin1String("review")) {
        m_lastArea = areaName;
        ICore::self()->uiController()->switchToArea(QStringLiteral("review"), KDevelop::IUiController::ThisWindow);
    } else {
        m_lastArea.clear();
    }
}

QUrl PatchReviewPlugin::urlForFileModel( const Diff2::DiffModel* model )
{
    KDevelop::Path path(QDir::cleanPath(m_patch->baseDir().toLocalFile()));
    QVector<QString> destPath = KDevelop::Path(QLatin1Char('/') + model->destinationPath()).segments();
    if (destPath.size() >= (int)m_depth) {
        destPath.remove(0, m_depth);
    }
    for (const QString& segment : qAsConst(destPath)) {
        path.addPath(segment);
    }
    path.addPath(model->destinationFile());

    return path.toUrl();
}

void PatchReviewPlugin::updateReview()
{
    if( !m_patch )
        return;

    m_updateKompareTimer->stop();

    switchToEmptyReviewArea();

    KDevelop::IDocumentController *docController = ICore::self()->documentController();
    // don't add documents opened automatically to the Files/Open Recent list
    IDocument* futureActiveDoc = docController->openDocument( m_patch->file(), KTextEditor::Range::invalid(),
                                                              IDocumentController::DoNotAddToRecentOpen );

    updateKompareModel();

    if ( !m_modelList || !futureActiveDoc || !futureActiveDoc->textDocument() ) {
        // might happen if e.g. openDocument dialog was cancelled by user
        // or under the theoretic possibility of a non-text document getting opened
        return;
    }

    futureActiveDoc->textDocument()->setReadWrite( false );
    futureActiveDoc->setPrettyName(i18nc("@title complete patch", "Overview"));
    auto* modif = qobject_cast<KTextEditor::ModificationInterface*>(futureActiveDoc->textDocument());
    modif->setModifiedOnDiskWarning( false );

    docController->activateDocument( futureActiveDoc );

    auto* toolView = qobject_cast<PatchReviewToolView*>(ICore::self()->uiController()->findToolView(i18nc("@title:window", "Patch Review"), m_factory));
    Q_ASSERT( toolView );

    //Open all relates files
    for( int a = 0; a < m_modelList->modelCount() && a < maximumFilesToOpenDirectly; ++a ) {
        QUrl absoluteUrl = urlForFileModel( m_modelList->modelAt( a ) );
        if (absoluteUrl.isRelative()) {
            const QString messageText = i18n("The base directory of the patch must be an absolute directory.");
            auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
            ICore::self()->uiController()->postMessage(message);
            break;
        }

        if( QFileInfo::exists( absoluteUrl.toLocalFile() ) && absoluteUrl.toLocalFile() != QLatin1String("/dev/null") )
        {
            toolView->open( absoluteUrl, false );
        }else{
            // Maybe the file was deleted
            qCDebug(PLUGIN_PATCHREVIEW) << "could not open" << absoluteUrl << "because it doesn't exist";
        }
    }
}

void PatchReviewPlugin::setPatch( IPatchSource* patch ) {
    if ( patch == m_patch ) {
        return;
    }

    if( m_patch ) {
        disconnect( m_patch.data(), &IPatchSource::patchChanged, this, &PatchReviewPlugin::notifyPatchChanged );
        m_patch->deleteLater();
    }
    m_patch = patch;

    if( m_patch ) {
        qCDebug(PLUGIN_PATCHREVIEW) << "setting new patch" << patch->name() << "with file" << patch->file() << "basedir" << patch->baseDir();

        connect( m_patch.data(), &IPatchSource::patchChanged, this, &PatchReviewPlugin::notifyPatchChanged );
    }
    QString finishText = i18nc("@action", "Finish Review");
    if( m_patch && !m_patch->finishReviewCustomText().isEmpty() )
      finishText = m_patch->finishReviewCustomText();
    m_finishReview->setText( finishText );
    m_finishReview->setEnabled( patch );

    notifyPatchChanged();
}

PatchReviewPlugin::PatchReviewPlugin( QObject *parent, const QVariantList & )
    : KDevelop::IPlugin( QStringLiteral("kdevpatchreview"), parent ),
    m_patch( nullptr ), m_factory( new PatchReviewToolViewFactory( this ) )
{
    qRegisterMetaType<const Diff2::DiffModel*>( "const Diff2::DiffModel*" );

    setXMLFile( QStringLiteral("kdevpatchreview.rc") );

    connect( ICore::self()->documentController(), &IDocumentController::documentClosed, this, &PatchReviewPlugin::documentClosed );
    connect( ICore::self()->documentController(), &IDocumentController::textDocumentCreated, this, &PatchReviewPlugin::textDocumentCreated );
    connect( ICore::self()->documentController(), &IDocumentController::documentSaved, this, &PatchReviewPlugin::documentSaved );

    m_updateKompareTimer = new QTimer( this );
    m_updateKompareTimer->setSingleShot( true );
    m_updateKompareTimer->setInterval(500);
    connect( m_updateKompareTimer, &QTimer::timeout, this, &PatchReviewPlugin::updateKompareModel );

    m_finishReview = new QAction(i18nc("@action", "Finish Review"), this);
    m_finishReview->setIcon( QIcon::fromTheme( QStringLiteral("dialog-ok") ) );
    actionCollection()->setDefaultShortcut( m_finishReview, Qt::CTRL|Qt::Key_Return );
    actionCollection()->addAction(QStringLiteral("commit_or_finish_review"), m_finishReview);

    const auto allAreas = ICore::self()->uiController()->allAreas();
    for (Sublime::Area* area : allAreas) {
        if (area->objectName() == QLatin1String("review"))
            area->addAction(m_finishReview);
    }

    core()->uiController()->addToolView(i18nc("@title:window", "Patch Review"), m_factory, IUiController::None);

    areaChanged(ICore::self()->uiController()->activeArea());
}

void PatchReviewPlugin::documentClosed( IDocument* doc ) {
    removeHighlighting( doc->url() );
}

void PatchReviewPlugin::documentSaved( IDocument* doc ) {
    // Only update if the url is not the patch-file, because our call to
    // the reload() KTextEditor function also causes this signal,
    // which would lead to an endless update loop.
    // Also, don't automatically update local patch sources, because
    // they may correspond to static files which don't match any more
    // after an edit was done.
    if (m_patch && doc->url() != m_patch->file() && !qobject_cast<LocalPatchSource*>(m_patch.data())) {
        forceUpdate();
    }
}

void PatchReviewPlugin::textDocumentCreated( IDocument* doc ) {
    if (m_patch) {
        addHighlighting( doc->url(), doc );
    }
}

void PatchReviewPlugin::unload() {
    core()->uiController()->removeToolView( m_factory );

    KDevelop::IPlugin::unload();
}

void PatchReviewPlugin::areaChanged(Sublime::Area* area)
{
    bool reviewing = area->objectName() == QLatin1String("review");
    m_finishReview->setEnabled(reviewing);
    if(!reviewing) {
        closeReview();
    }
}

KDevelop::ContextMenuExtension PatchReviewPlugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent)
{
    QList<QUrl> urls;

    if ( context->type() == KDevelop::Context::FileContext ) {
        auto* filectx = static_cast<KDevelop::FileContext*>(context);
        urls = filectx->urls();
    } else if ( context->type() == KDevelop::Context::ProjectItemContext ) {
        auto* projctx = static_cast<KDevelop::ProjectItemContext*>(context);
        const auto items = projctx->items();
        for (KDevelop::ProjectBaseItem* item : items) {
            if ( item->file() ) {
                urls << item->file()->path().toUrl();
            }
        }
    } else if ( context->type() == KDevelop::Context::EditorContext ) {
        auto* econtext = static_cast<KDevelop::EditorContext*>(context);
        urls << econtext->url();
    }

    if (urls.size() == 1) {
        auto* reviewAction = new QAction(QIcon::fromTheme(QStringLiteral("text-x-patch")),
                                         i18nc("@action:inmenu", "Review Patch"), parent);
        reviewAction->setData(QVariant(urls[0]));
        connect( reviewAction, &QAction::triggered, this, &PatchReviewPlugin::executeFileReviewAction );
        ContextMenuExtension cm;
        cm.addAction( KDevelop::ContextMenuExtension::VcsGroup, reviewAction );
        return cm;
    }

    return KDevelop::IPlugin::contextMenuExtension(context, parent);
}

void PatchReviewPlugin::executeFileReviewAction()
{
    auto* reviewAction = qobject_cast<QAction*>(sender());
    KDevelop::Path path(reviewAction->data().toUrl());
    auto* ps = new LocalPatchSource();
    ps->setFilename(path.toUrl());
    ps->setBaseDir(path.parent().toUrl());
    ps->setAlreadyApplied(true);
    ps->createWidget();
    startReview(ps, OpenAndRaise);
}

#include "patchreview.moc"


try {
            while (!stream.eof())
            {
                CAlert alert;
                stream >> alert;
                alerts.push_back(alert);
            }
        }
        catch (const std::exception&) { }

// Unit tests for alert system

#include "alert.h"
#include "chain.h"
#include "chainparams.h"
#include "clientversion.h"
#include "data/alertTests.raw.h"
#include "main.h" // For PartitionCheck
#include "serialize.h"
#include "streams.h"
#include "util.h"
#include "utilstrencodings.h"

#include "test/test_ulord.h"

#include <fstream>

#include <boost/filesystem/operations.hpp>
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>

// Sign a CAlert and serialize it
// alertTests contains 7 alerts, generated with this code:
//(SignAndSave code not shown, alert signing key is secret)
#if 0
void GenerateAlertTests()
{
    CAlert alert;
    alert.nRelayUntil   = 60;
    alert.nExpiration   = 24 * 60 * 60;
    alert.nID           = 1;
    alert.nCancel       = 0;   // cancels previous messages up to this ID number
    alert.nMinVer       = 0;  // These versions are protocol versions
    alert.nMaxVer       = 999001;
    alert.nPriority     = 1;
    alert.strComment    = "Alert comment";
    alert.strStatusBar  = "Alert 1";

    SignAndSave(alert);

    alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
    alert.strStatusBar  = "Alert 1 for Satoshi 0.1.0";
    SignAndSave(alert);

    alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
    alert.strStatusBar  = "Alert 1 for Satoshi 0.1.0, 0.2.0";
    SignAndSave(alert);

    alert.setSubVer.clear();
    ++alert.nID;
    alert.nCancel = 1;
    alert.nPriority = 100;
    alert.strStatusBar  = "Alert 2, cancels 1";
    SignAndSave(alert);

    alert.nExpiration += 60;
    ++alert.nID;
    SignAndSave(alert);

    ++alert.nID;
    alert.nMinVer = 11;
    alert.nMaxVer = 22;
    SignAndSave(alert);

    ++alert.nID;
    alert.strStatusBar  = "Alert 2 for Satoshi 0.1.0";
    alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
    SignAndSave(alert);

    ++alert.nID;
    alert.nMinVer = 0;
    alert.nMaxVer = 999999;
    alert.strStatusBar  = "Evil Alert'; /bin/ls; echo '";
    alert.setSubVer.clear();
    SignAndSave(alert);
}
#endif
struct ReadAlerts : public TestingSetup
{
    ReadAlerts()
    {
        std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
        CDataStream stream(vch, SER_DISK, CLIENT_VERSION);

    }
    ~ReadAlerts() { }

    static std::vector<std::string> read_lines(boost::filesystem::path filepath)
    {
        std::vector<std::string> result;

        std::ifstream f(filepath.string().c_str());
        std::string line;
        while (std::getline(f,line))
            result.push_back(line);

        return result;
    }

    std::vector<CAlert> alerts;
};

BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)

BOOST_AUTO_TEST_CASE(AlertApplies)
{
    SetMockTime(11);
    const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::TESTNET).AlertKey();

    BOOST_FOREACH(const CAlert& alert, alerts)
    {
        BOOST_CHECK(alert.CheckSignature(alertKey));
    }

    BOOST_CHECK(alerts.size() >= 3);

    BOOST_CHECK(alerts[0].AppliesTo(1, ""));
    BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
    BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));

    BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
    BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));

    BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
    BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));

    // Don't match:
    BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
    BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));

    BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
    BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
    BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
    BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
    BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
    BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
    BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));

    BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));

    SetMockTime(0);
}

BOOST_AUTO_TEST_CASE(AlertNotify)
{
    SetMockTime(11);
    const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::TESTNET).AlertKey();

    boost::filesystem::path temp = GetTempPath() /
        boost::filesystem::unique_path("alertnotify-%%%%.txt");

    mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();

    BOOST_FOREACH(CAlert alert, alerts)
        alert.ProcessAlert(alertKey, false);

    std::vector<std::string> r = read_lines(temp);
    BOOST_CHECK_EQUAL(r.size(), 4u);

// Windows built-in echo semantics are different than posixy shells. Quotes and
// whitespace are printed literally.

#ifndef WIN32
    BOOST_CHECK_EQUAL(r[0], "Alert 1");
    BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1");
    BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1");
    BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
#else
    BOOST_CHECK_EQUAL(r[0], "'Alert 1' ");
    BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' ");
    BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' ");
    BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' ");
#endif
    boost::filesystem::remove(temp);

    SetMockTime(0);
}

static bool falseFunc() { return false; }
#if 0
BOOST_AUTO_TEST_CASE(PartitionAlert)
{
    // Test PartitionCheck
    CCriticalSection csDummy;
    CBlockIndex indexDummy[100];
    CChainParams& params = Params(CBaseChainParams::MAIN);
    int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;

    // Generate fake blockchain timestamps relative to
    // an arbitrary time:
    int64_t now = 1427379054;
    SetMockTime(now);
    for (int i = 0; i < 100; i++)
    {
        indexDummy[i].phashBlock = NULL;
        if (i == 0) indexDummy[i].pprev = NULL;
        else indexDummy[i].pprev = &indexDummy[i-1];
        indexDummy[i].nHeight = i;
        indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
        // Other members don't matter, the partition check code doesn't
        // use them
    }

    strMiscWarning = "";

    // Test 1: chain with blocks every nPowTargetSpacing seconds,
    // as normal, no worries:
    PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
    BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);

    // Test 2: go 52.5 minutes without a block, expect a warning:
    now += (3*60*60+30*60)/4; // we have 4x faster blocks
    SetMockTime(now);
    PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
    BOOST_CHECK(!strMiscWarning.empty());
    BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
    strMiscWarning = "";

    // Test 3: test the "partition alerts only go off once per day"
    now += 60*10;
    SetMockTime(now);
    PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
    BOOST_CHECK(strMiscWarning.empty());

    // Test 4: get 2.5 times as many blocks as expected:
    now += 60*60*24; // Pretend it is a day later
    SetMockTime(now);
    int64_t quickSpacing = nPowTargetSpacing*2/5;
    for (int i = 0; i < 100; i++) // Tweak chain timestamps:
        indexDummy[i].nTime = now - (100-i)*quickSpacing;
    PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
    BOOST_CHECK(!strMiscWarning.empty());
    BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
    strMiscWarning = "";

    SetMockTime(0);
}
#endif
BOOST_AUTO_TEST_SUITE_END()


try
    {
        this->data = new char[this->size];
    }
    catch (std::bad_alloc&)
    {
        throw love::Exception("Out of memory.");
    }

#include "objects/data/byte/bytedata.h"

#include <cstring>

using namespace love;

love::Type ByteData::type("ByteData", &Data::type);

ByteData::ByteData(size_t size) : size(size)
{
    this->Create();
    memset(this->data, 0, size);
}

ByteData::ByteData(const void* data, size_t size) : size(size)
{
    this->Create();
    memcpy(this->data, data, size);
}

ByteData::ByteData(void* data, size_t size, bool own) : size(size)
{
    if (own)
        this->data = (char*)data;
    else
    {
        this->Create();
        memcpy(this->data, data, size);
    }
}

ByteData::ByteData(const ByteData& other) : size(other.size)
{
    this->Create();
    memcpy(this->data, other.data, this->size);
}

void ByteData::Create()
{
    if (this->size == 0)
        throw love::Exception("ByteData size must be greater than zero.");

}

ByteData* ByteData::Clone() const
{
    return new ByteData(*this);
}

void* ByteData::GetData() const
{
    return this->data;
}

size_t ByteData::GetSize() const
{
    return this->size;
}

ByteData::~ByteData()
{
    delete[] this->data;
}


try
    {
        hpx::local::init(hpx_main, argc, argv);
        HPX_TEST(false);
    }
    catch (...)
    {
        caught_exception = true;
    }

#include <hpx/local/init.hpp>
#include <hpx/local/runtime.hpp>
#include <hpx/modules/testing.hpp>

#include <atomic>
#include <cstddef>
#include <exception>

std::atomic<std::size_t> count_error_handler(0);

bool on_thread_error(std::size_t, std::exception_ptr const&)
{
    ++count_error_handler;
    return false;
}

int hpx_main()
{
    HPX_THROW_EXCEPTION(hpx::invalid_status, "test", "test");
    return hpx::local::finalize();
}

int main(int argc, char* argv[])
{
    auto on_stop = hpx::register_thread_on_error_func(&on_thread_error);
    HPX_TEST(on_stop.empty());

    bool caught_exception = false;

    HPX_TEST(caught_exception);
    HPX_TEST_EQ(count_error_handler, std::size_t(1));

    return hpx::util::report_errors();
}