<commit_before>/*
    This file is part of Akregator.

    Copyright (C) 2008 Frank Osterfeld <osterfeld@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "expireitemscommand.h"

#include "articlejobs.h"
#include "feed.h"
#include "feedlist.h"

#include <QPointer>
#include <QSet>
#include <QTimer>

#include <cassert>

using namespace Akregator;

class ExpireItemsCommand::Private
{
    ExpireItemsCommand* const q;
public:
    explicit Private( ExpireItemsCommand* qq );

    void createDeleteJobs();
    void addDeleteJobForFeed( Feed* feed );
    void jobFinished( KJob* );

    QPointer<FeedList> m_feedList;
    QVector<int> m_feeds;
    QSet<KJob*> m_jobs;
};

ExpireItemsCommand::Private::Private( ExpireItemsCommand* qq ) : q( qq ), m_feedList()
{

}

void ExpireItemsCommand::Private::addDeleteJobForFeed( Feed* feed )
{
    assert( feed );
    ArticleDeleteJob* job = new ArticleDeleteJob( q );
    connect( job, SIGNAL( finished( KJob* ) ), q, SLOT( jobFinished( KJob* ) ) );
    m_jobs.insert( job );
    feed->deleteExpiredArticles( job );
    job->start();
}

void ExpireItemsCommand::Private::jobFinished( KJob* job )
{
    assert( !m_jobs.isEmpty() );
    m_jobs.remove( job );
    emit q->progress( ( ( m_feeds.count() - m_jobs.count() ) * 100 ) / m_feeds.count(), QString() );
    if ( m_jobs.isEmpty() )
        q->done();
}

void ExpireItemsCommand::Private::createDeleteJobs()
{
    assert( m_jobs.isEmpty() );
    if ( m_feeds.isEmpty() )
    {
        q->done();
        return;
    }

    Q_FOREACH ( const int i, m_feeds )
    {
        Feed* const feed = qobject_cast<Feed*>( m_feedList->findByID( i ) );
        if ( feed )
            addDeleteJobForFeed( feed );
    }
}

ExpireItemsCommand::ExpireItemsCommand( QObject* parent ) : Command( parent ), d( new Private( this ) )
{
}

ExpireItemsCommand::~ExpireItemsCommand()
{
    delete d;
}

void ExpireItemsCommand::setFeedList( FeedList* feedList )
{
    d->m_feedList = feedList;
}

FeedList* ExpireItemsCommand::feedList() const
{
    return d->m_feedList;
}

void ExpireItemsCommand::setFeeds( const QVector<int>& feeds )
{
    d->m_feeds = feeds;
}

QVector<int> ExpireItemsCommand::feeds() const
{
    return d->m_feeds;
}

void ExpireItemsCommand::doAbort()
{
    Q_FOREACH( KJob* const i, d->m_jobs )
        i->kill();
}

void ExpireItemsCommand::doStart()
{
    QTimer::singleShot( 0, this, SLOT( createDeleteJobs() ) );
}

#include "expireitemscommand.moc"
<commit_msg>make expiry not crash if the feed list was replaced<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2008 Frank Osterfeld <osterfeld@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "expireitemscommand.h"

#include "articlejobs.h"
#include "feed.h"
#include "feedlist.h"

#include <KDebug>

#include <QPointer>
#include <QSet>
#include <QTimer>

#include <cassert>

using namespace Akregator;

class ExpireItemsCommand::Private
{
    ExpireItemsCommand* const q;
public:
    explicit Private( ExpireItemsCommand* qq );

    void createDeleteJobs();
    void addDeleteJobForFeed( Feed* feed );
    void jobFinished( KJob* );

    QPointer<FeedList> m_feedList;
    QVector<int> m_feeds;
    QSet<KJob*> m_jobs;
};

ExpireItemsCommand::Private::Private( ExpireItemsCommand* qq ) : q( qq ), m_feedList()
{

}

void ExpireItemsCommand::Private::addDeleteJobForFeed( Feed* feed )
{
    assert( feed );
    ArticleDeleteJob* job = new ArticleDeleteJob( q );
    connect( job, SIGNAL( finished( KJob* ) ), q, SLOT( jobFinished( KJob* ) ) );
    m_jobs.insert( job );
    feed->deleteExpiredArticles( job );
    job->start();
}

void ExpireItemsCommand::Private::jobFinished( KJob* job )
{
    assert( !m_jobs.isEmpty() );
    m_jobs.remove( job );
    emit q->progress( ( ( m_feeds.count() - m_jobs.count() ) * 100 ) / m_feeds.count(), QString() );
    if ( m_jobs.isEmpty() )
        q->done();
}

void ExpireItemsCommand::Private::createDeleteJobs()
{
    assert( m_jobs.isEmpty() );
    if ( m_feeds.isEmpty() || !m_feedList )
    {
        if ( !m_feedList )
            kWarning() << "Associated feed list was deleted, could not expire items";
        q->done();
        return;
    }

    Q_FOREACH ( const int i, m_feeds )
    {
        Feed* const feed = qobject_cast<Feed*>( m_feedList->findByID( i ) );
        if ( feed )
            addDeleteJobForFeed( feed );
    }
}

ExpireItemsCommand::ExpireItemsCommand( QObject* parent ) : Command( parent ), d( new Private( this ) )
{
}

ExpireItemsCommand::~ExpireItemsCommand()
{
    delete d;
}

void ExpireItemsCommand::setFeedList( FeedList* feedList )
{
    d->m_feedList = feedList;
}

FeedList* ExpireItemsCommand::feedList() const
{
    return d->m_feedList;
}

void ExpireItemsCommand::setFeeds( const QVector<int>& feeds )
{
    d->m_feeds = feeds;
}

QVector<int> ExpireItemsCommand::feeds() const
{
    return d->m_feeds;
}

void ExpireItemsCommand::doAbort()
{
    Q_FOREACH( KJob* const i, d->m_jobs )
        i->kill();
}

void ExpireItemsCommand::doStart()
{
    QTimer::singleShot( 0, this, SLOT( createDeleteJobs() ) );
}

#include "expireitemscommand.moc"
<|endoftext|>


<commit_before><commit_msg>minor<commit_after><|endoftext|>


<commit_before><commit_msg>compile<commit_after><|endoftext|>


<commit_before> /*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef PCL_STANDALONE_MARCHING_CUBES_IMPL_HPP_
#define PCL_STANDALONE_MARCHING_CUBES_IMPL_HPP_

#include <pcl/gpu/kinfu_large_scale/standalone_marching_cubes.h>

///////////////////////////////////////////////////////////////////////////////
template <typename PointT>
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::StandaloneMarchingCubes (int new_voxels_x, int new_voxels_y, int new_voxels_z, float new_volume_size)
{
  voxels_x_ = new_voxels_x;
  voxels_y_ = new_voxels_y;
  voxels_z_ = new_voxels_z;
  volume_size_ = new_volume_size;

  ///Creating GPU TSDF Volume instance
  const Eigen::Vector3f volume_size = Eigen::Vector3f::Constant (volume_size_);
  // std::cout << "VOLUME SIZE IS " << volume_size_ << std::endl;
  const Eigen::Vector3i volume_resolution (voxels_x_, voxels_y_, voxels_z_);
  tsdf_volume_gpu_ = TsdfVolume::Ptr ( new TsdfVolume (volume_resolution) );
  tsdf_volume_gpu_->setSize (volume_size);

  ///Creating CPU TSDF Volume instance
  int tsdf_total_size = voxels_x_ * voxels_y_ * voxels_z_;
  tsdf_volume_cpu_= std::vector<int> (tsdf_total_size,0);

  mesh_counter_ = 0;
}

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

template <typename PointT> typename pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::MeshPtr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::getMeshFromTSDFCloud (const PointCloud &cloud)
{

  //Clearing TSDF GPU and cPU
  const Eigen::Vector3f volume_size = Eigen::Vector3f::Constant (volume_size_);
    std::cout << "VOLUME SIZE IS " << volume_size_ << std::endl;
  const Eigen::Vector3i volume_resolution (voxels_x_, voxels_y_, voxels_z_);

  //Clear values in TSDF Volume GPU
  tsdf_volume_gpu_->reset (); // This one uses the same tsdf volume but clears it before loading new values. This one is our friend.

  //Clear values in TSDF Volume CPU
  int tsdf_total_size = voxels_x_ * voxels_y_ * voxels_z_;
  tsdf_volume_cpu_= std::vector<int> (tsdf_total_size,0);

  //Loading values to GPU
  loadTsdfCloudToGPU (cloud);

  //Creating and returning mesh
  return ( runMarchingCubes () );

}

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

//template <typename PointT> std::vector< typename pcl::gpu::StandaloneMarchingCubes<PointT>::MeshPtr >
template <typename PointT> void
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::getMeshesFromTSDFVector (const std::vector<PointCloudPtr> &tsdf_clouds, const std::vector<Eigen::Vector3f> &tsdf_offsets)
{
  std::vector< MeshPtr > meshes_vector;

  int max_iterations = std::min( tsdf_clouds.size (), tsdf_offsets.size () ); //Safety check
  PCL_INFO ("There are %d cubes to be processed \n", max_iterations);
  float cell_size = volume_size_ / voxels_x_;

  int mesh_counter = 0;

  for(int i = 0; i < max_iterations; ++i)
  {
    PCL_INFO ("Processing cube number %d\n", i);

    //Making cloud local
    Eigen::Affine3f cloud_transform;

    float originX = (tsdf_offsets[i]).x();
    float originY = (tsdf_offsets[i]).y();
    float originZ = (tsdf_offsets[i]).z();

    cloud_transform.linear ().setIdentity ();
    cloud_transform.translation ()[0] = -originX;
    cloud_transform.translation ()[1] = -originY;
    cloud_transform.translation ()[2] = -originZ;

    transformPointCloud (*tsdf_clouds[i], *tsdf_clouds[i], cloud_transform);

    //Get mesh
    MeshPtr tmp = getMeshFromTSDFCloud (*tsdf_clouds[i]);

    if(tmp != 0)
    {
       meshes_vector.push_back (tmp);
       mesh_counter++;
    }
    else
    {
      PCL_INFO ("This cloud returned no faces, we skip it!\n");
      continue;
    }

    //Making cloud global
    cloud_transform.translation ()[0] = originX * cell_size;
    cloud_transform.translation ()[1] = originY * cell_size;
    cloud_transform.translation ()[2] = originZ * cell_size;

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tmp_ptr (new pcl::PointCloud<pcl::PointXYZ>);
    fromROSMsg ( (meshes_vector.back () )->cloud, *cloud_tmp_ptr);

    transformPointCloud (*cloud_tmp_ptr, *cloud_tmp_ptr, cloud_transform);

    toROSMsg (*cloud_tmp_ptr, (meshes_vector.back () )->cloud);

    std::stringstream name;
    name << "mesh_" << mesh_counter << ".ply";
    PCL_INFO ("Saving mesh...%d \n", mesh_counter);
    pcl::io::savePLYFile (name.str (), *(meshes_vector.back ()));

  }
  return;
}

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

template <typename PointT> pcl::gpu::kinfuLS::TsdfVolume::Ptr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::tsdfVolumeGPU ()
{
  return (tsdf_volume_gpu_);
}

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

template <typename PointT> std::vector<int>& //todo
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::tsdfVolumeCPU ()
{
  return (tsdf_volume_cpu_);
}

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

template <typename PointT> void
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::loadTsdfCloudToGPU (const PointCloud &cloud)
{
  //Converting Values
  convertTsdfVectors (cloud, tsdf_volume_cpu_);

  //Uploading data to GPU
	int cubeColumns = voxels_x_;
  tsdf_volume_gpu_->data ().upload (tsdf_volume_cpu_, cubeColumns);
}

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

template <typename PointT> void
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::convertTsdfVectors (const PointCloud &cloud, std::vector<int> &output)
{
	  const int DIVISOR = 32767;     // SHRT_MAX;

    ///For every point in the cloud
#pragma omp parallel for

	for(int i = 0; i < (int) cloud.points.size (); ++i)
	{
	  int x = cloud.points[i].x;
	  int y = cloud.points[i].y;
	  int z = cloud.points[i].z;

	  if(x > 0  && x < voxels_x_ && y > 0 && y < voxels_y_ && z > 0 && z < voxels_z_)
	  {
	  ///Calculate the index to write to
	  int dst_index = x + voxels_x_ * y + voxels_y_ * voxels_x_ * z;

	    short2& elem = *reinterpret_cast<short2*> (&output[dst_index]);
	    elem.x = static_cast<short> (cloud.points[i].intensity * DIVISOR);
	    elem.y = static_cast<short> (1);
	  }
  }
}

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

template <typename PointT> typename pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::MeshPtr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::convertTrianglesToMesh (const pcl::gpu::DeviceArray<pcl::PointXYZ>& triangles)
{
  if (triangles.empty () )
  {
    return MeshPtr ();
  }

  pcl::PointCloud<pcl::PointXYZ> cloud;
  cloud.width  = (int)triangles.size ();
  cloud.height = 1;
  triangles.download (cloud.points);

  boost::shared_ptr<pcl::PolygonMesh> mesh_ptr ( new pcl::PolygonMesh () );

  pcl::toROSMsg (cloud, mesh_ptr->cloud);

  mesh_ptr->polygons.resize (triangles.size () / 3);
  for (size_t i = 0; i < mesh_ptr->polygons.size (); ++i)
  {
    pcl::Vertices v;
    v.vertices.push_back (i*3+0);
    v.vertices.push_back (i*3+2);
    v.vertices.push_back (i*3+1);
    mesh_ptr->polygons[i] = v;
  }
  return (mesh_ptr);
}

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

template <typename PointT> typename pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::MeshPtr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::runMarchingCubes ()
{
  //Preparing the pointers and variables
  const TsdfVolume::Ptr tsdf_volume_const_ = tsdf_volume_gpu_;
  pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_buffer_device_;

  //Creating Marching cubes instance
  MarchingCubes::Ptr marching_cubes_ = MarchingCubes::Ptr ( new MarchingCubes() );

  //Running marching cubes
  pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_device = marching_cubes_->run (*tsdf_volume_const_, triangles_buffer_device_);

  //Creating mesh
  boost::shared_ptr<pcl::PolygonMesh> mesh_ptr_ = convertTrianglesToMesh (triangles_device);

  if(mesh_ptr_ != 0)
  {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tmp_ptr (new pcl::PointCloud<pcl::PointXYZ>);
    fromROSMsg ( mesh_ptr_->cloud, *cloud_tmp_ptr);
  }
  return (mesh_ptr_);
}

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

#endif // PCL_STANDALONE_MARCHING_CUBES_IMPL_HPP_

<commit_msg>fix bad reinit on a vector<commit_after> /*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef PCL_STANDALONE_MARCHING_CUBES_IMPL_HPP_
#define PCL_STANDALONE_MARCHING_CUBES_IMPL_HPP_

#include <pcl/gpu/kinfu_large_scale/standalone_marching_cubes.h>

///////////////////////////////////////////////////////////////////////////////
template <typename PointT>
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::StandaloneMarchingCubes (int new_voxels_x, int new_voxels_y, int new_voxels_z, float new_volume_size)
{
  voxels_x_ = new_voxels_x;
  voxels_y_ = new_voxels_y;
  voxels_z_ = new_voxels_z;
  volume_size_ = new_volume_size;

  ///Creating GPU TSDF Volume instance
  const Eigen::Vector3f volume_size = Eigen::Vector3f::Constant (volume_size_);
  // std::cout << "VOLUME SIZE IS " << volume_size_ << std::endl;
  const Eigen::Vector3i volume_resolution (voxels_x_, voxels_y_, voxels_z_);
  tsdf_volume_gpu_ = TsdfVolume::Ptr ( new TsdfVolume (volume_resolution) );
  tsdf_volume_gpu_->setSize (volume_size);

  ///Creating CPU TSDF Volume instance
  int tsdf_total_size = voxels_x_ * voxels_y_ * voxels_z_;
  tsdf_volume_cpu_= std::vector<int> (tsdf_total_size,0);

  mesh_counter_ = 0;
}

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

template <typename PointT> typename pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::MeshPtr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::getMeshFromTSDFCloud (const PointCloud &cloud)
{

  //Clearing TSDF GPU and cPU
  const Eigen::Vector3f volume_size = Eigen::Vector3f::Constant (volume_size_);
    std::cout << "VOLUME SIZE IS " << volume_size_ << std::endl;
  const Eigen::Vector3i volume_resolution (voxels_x_, voxels_y_, voxels_z_);

  //Clear values in TSDF Volume GPU
  tsdf_volume_gpu_->reset (); // This one uses the same tsdf volume but clears it before loading new values. This one is our friend.

  //Clear values in TSDF Volume CPU
  fill (tsdf_volume_cpu_.begin (), tsdf_volume_cpu_.end (), 0);

  //Loading values to GPU
  loadTsdfCloudToGPU (cloud);

  //Creating and returning mesh
  return ( runMarchingCubes () );

}

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

//template <typename PointT> std::vector< typename pcl::gpu::StandaloneMarchingCubes<PointT>::MeshPtr >
template <typename PointT> void
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::getMeshesFromTSDFVector (const std::vector<PointCloudPtr> &tsdf_clouds, const std::vector<Eigen::Vector3f> &tsdf_offsets)
{
  std::vector< MeshPtr > meshes_vector;

  int max_iterations = std::min( tsdf_clouds.size (), tsdf_offsets.size () ); //Safety check
  PCL_INFO ("There are %d cubes to be processed \n", max_iterations);
  float cell_size = volume_size_ / voxels_x_;

  int mesh_counter = 0;

  for(int i = 0; i < max_iterations; ++i)
  {
    PCL_INFO ("Processing cube number %d\n", i);

    //Making cloud local
    Eigen::Affine3f cloud_transform;

    float originX = (tsdf_offsets[i]).x();
    float originY = (tsdf_offsets[i]).y();
    float originZ = (tsdf_offsets[i]).z();

    cloud_transform.linear ().setIdentity ();
    cloud_transform.translation ()[0] = -originX;
    cloud_transform.translation ()[1] = -originY;
    cloud_transform.translation ()[2] = -originZ;

    transformPointCloud (*tsdf_clouds[i], *tsdf_clouds[i], cloud_transform);

    //Get mesh
    MeshPtr tmp = getMeshFromTSDFCloud (*tsdf_clouds[i]);

    if(tmp != 0)
    {
       meshes_vector.push_back (tmp);
       mesh_counter++;
    }
    else
    {
      PCL_INFO ("This cloud returned no faces, we skip it!\n");
      continue;
    }

    //Making cloud global
    cloud_transform.translation ()[0] = originX * cell_size;
    cloud_transform.translation ()[1] = originY * cell_size;
    cloud_transform.translation ()[2] = originZ * cell_size;

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tmp_ptr (new pcl::PointCloud<pcl::PointXYZ>);
    fromROSMsg ( (meshes_vector.back () )->cloud, *cloud_tmp_ptr);

    transformPointCloud (*cloud_tmp_ptr, *cloud_tmp_ptr, cloud_transform);

    toROSMsg (*cloud_tmp_ptr, (meshes_vector.back () )->cloud);

    std::stringstream name;
    name << "mesh_" << mesh_counter << ".ply";
    PCL_INFO ("Saving mesh...%d \n", mesh_counter);
    pcl::io::savePLYFile (name.str (), *(meshes_vector.back ()));

  }
  return;
}

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

template <typename PointT> pcl::gpu::kinfuLS::TsdfVolume::Ptr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::tsdfVolumeGPU ()
{
  return (tsdf_volume_gpu_);
}

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

template <typename PointT> std::vector<int>& //todo
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::tsdfVolumeCPU ()
{
  return (tsdf_volume_cpu_);
}

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

template <typename PointT> void
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::loadTsdfCloudToGPU (const PointCloud &cloud)
{
  //Converting Values
  convertTsdfVectors (cloud, tsdf_volume_cpu_);

  //Uploading data to GPU
	int cubeColumns = voxels_x_;
  tsdf_volume_gpu_->data ().upload (tsdf_volume_cpu_, cubeColumns);
}

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

template <typename PointT> void
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::convertTsdfVectors (const PointCloud &cloud, std::vector<int> &output)
{
	  const int DIVISOR = 32767;     // SHRT_MAX;

    ///For every point in the cloud
#pragma omp parallel for

	for(int i = 0; i < (int) cloud.points.size (); ++i)
	{
	  int x = cloud.points[i].x;
	  int y = cloud.points[i].y;
	  int z = cloud.points[i].z;

	  if(x > 0  && x < voxels_x_ && y > 0 && y < voxels_y_ && z > 0 && z < voxels_z_)
	  {
	  ///Calculate the index to write to
	  int dst_index = x + voxels_x_ * y + voxels_y_ * voxels_x_ * z;

	    short2& elem = *reinterpret_cast<short2*> (&output[dst_index]);
	    elem.x = static_cast<short> (cloud.points[i].intensity * DIVISOR);
	    elem.y = static_cast<short> (1);
	  }
  }
}

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

template <typename PointT> typename pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::MeshPtr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::convertTrianglesToMesh (const pcl::gpu::DeviceArray<pcl::PointXYZ>& triangles)
{
  if (triangles.empty () )
  {
    return MeshPtr ();
  }

  pcl::PointCloud<pcl::PointXYZ> cloud;
  cloud.width  = (int)triangles.size ();
  cloud.height = 1;
  triangles.download (cloud.points);

  boost::shared_ptr<pcl::PolygonMesh> mesh_ptr ( new pcl::PolygonMesh () );

  pcl::toROSMsg (cloud, mesh_ptr->cloud);

  mesh_ptr->polygons.resize (triangles.size () / 3);
  for (size_t i = 0; i < mesh_ptr->polygons.size (); ++i)
  {
    pcl::Vertices v;
    v.vertices.push_back (i*3+0);
    v.vertices.push_back (i*3+2);
    v.vertices.push_back (i*3+1);
    mesh_ptr->polygons[i] = v;
  }
  return (mesh_ptr);
}

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

template <typename PointT> typename pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::MeshPtr
pcl::gpu::kinfuLS::StandaloneMarchingCubes<PointT>::runMarchingCubes ()
{
  //Preparing the pointers and variables
  const TsdfVolume::Ptr tsdf_volume_const_ = tsdf_volume_gpu_;
  pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_buffer_device_;

  //Creating Marching cubes instance
  MarchingCubes::Ptr marching_cubes_ = MarchingCubes::Ptr ( new MarchingCubes() );

  //Running marching cubes
  pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_device = marching_cubes_->run (*tsdf_volume_const_, triangles_buffer_device_);

  //Creating mesh
  boost::shared_ptr<pcl::PolygonMesh> mesh_ptr_ = convertTrianglesToMesh (triangles_device);

  if(mesh_ptr_ != 0)
  {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tmp_ptr (new pcl::PointCloud<pcl::PointXYZ>);
    fromROSMsg ( mesh_ptr_->cloud, *cloud_tmp_ptr);
  }
  return (mesh_ptr_);
}

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

#endif // PCL_STANDALONE_MARCHING_CUBES_IMPL_HPP_

<|endoftext|>


<commit_before>#include <boost/bind.hpp>
#include <gazebo/gazebo.hh>
#include <gazebo/physics/physics.hh>
#include <gazebo/common/common.hh>
#include <iostream>
using namespace std;

#define PI 3.1415926

namespace gazebo
{
	class ModelController1 : public ModelPlugin
	{
		public: ModelController1() : ModelPlugin(),DefaultKPID(0.01,0,0)
				{
					// Initialize variables
					WheelRadius =  0.045275;
					// A hint of model been initialized
					printf("Model Initiated\n");
				}
		public: void Load (physics::ModelPtr _parent, sdf::ElementPtr _sdf)
				{
					// Get all the pointers point to right objects
					this->model = _parent;
					this->JointWR = model->GetJoint("Right_wheel_hinge");
					this->JointWL = model->GetJoint("Left_wheel_hinge");
					this->JointWF = model->GetJoint("Front_wheel_hinge");
					this->JointCB = model->GetJoint("Center_hinge");
					// Setting the model state
					// Setting the maximium torque of the two wheels
					this->JointWR->SetMaxForce(0,1000);
					this->JointWL->SetMaxForce(0,1000);
					// Setting the maximium torque of the front wheel
					this->JointWF->SetMaxForce(0,1000);
					// Setting the maximium torque of the body bending joint
					this->JointCB->SetMaxForce(0,1000);
					// Testing codes
					this->JointWR->SetVelocity(0,0);
					this->JointWL->SetVelocity(0,0);
					math::Angle AngleInterested(0.5235987);
					this->JointCB->SetAngle(0,AngleInterested);
					// Event register, which will make the function be executed in each iteration
					this->updateConnection = event::Events::ConnectWorldUpdateBegin(boost::bind(&ModelController1::OnSystemRunning, this, _1));
				}
		// Testing function
		private: void OnSystemRunning(const common::UpdateInfo & /*_info*/)
				{
					double AngleValue;
					double force;
					// math::Angle angleOfJoint1;
					// angleOfJoint1 = Joint1->GetAngle(2);
					// AngleValue = angleOfJoint1.Degree();
					//****************************************************
					//common::Time TimeTmp;
					//physics::ModelState currentModelState(this->model);
					//TimeTmp = currentModelState.GetSimTime();
					//AngleValue = TimeTmp.Double();
					//***************************************************
					//AngleValue = this->RevolutionSpeedCal(Joint1,1);
					//cout<<"Angle:"<<AngleValue<<endl;
					//cout<<"Rotation Speed:"<<AngleValue<<" rad/s"<<endl;
					// math::Vector3 TmpPID(0,0,0);
					// PIDSpeedController(Joint1,0,PI/10,TmpPID);
					force = JointCB->GetForce(0);
					cout<<"The Angle of the bending:"<<force<<endl;
					// if (force > 0)
					// {
					// 	this->JointCB->SetVelocity(0,-0.1);
					// }else{
					// 	this->JointCB->SetVelocity(0,0);
					// }
					AngleValue = this->RevolutionSpeedCal(JointWR,0);
					cout<<"The real rotation rate is "<<AngleValue<<" rad/s"<<endl;

				}
		// This public function is used to control the speed of joint
		// The third parameter determine what kind of speed the user want to controll: 0 for rotation, 1 for linear, 2 for prismatic
		// If want to use the default PID controller parameters, just pass math::Vector3::Zero to KPID
		// If there is any errors or uncompleted information, the function will return false
		public: bool PIDSpeedController(const physics::JointPtr JointNTBC, const int AxisIndex, const double ExpectedSpeed,
										math::Vector3 KPID , const int SpeedType = 0, const double Radius = 0)
				{
					double SpeedCurrent;
					double TorqueIncrement;
					static double TotalTorque;

					// If PID parameters are not specified, set them to default
					if (KPID.x==0 && KPID.y==0 && KPID.z == 0)
					{
						KPID = DefaultKPID;
					}
					if (SpeedType == 0)
					{
						double SpeedErrorT0;
						static double SpeedErrorHis1T0 = 0, SpeedErrorHis2T0 = 0;
						static double SpeedErrorAccu = 0;

						SpeedCurrent = this->ComplementaryFilter(this->RevolutionSpeedCal(JointNTBC,AxisIndex));
						cout<<"SpeedCurrent = "<<SpeedCurrent<<endl;
						cout<<"ExpectedSpeed = "<<ExpectedSpeed<<endl;

						SpeedErrorT0 = ExpectedSpeed - SpeedCurrent;
						cout<<"SpeedErrorT0 = "<<SpeedErrorT0<<endl;
						//cout<<"The Current Error is "<<SpeedErrorT0<<" rad/s"<<endl;
						SpeedErrorAccu += SpeedErrorT0;

						TorqueIncrement = KPID.x*SpeedErrorT0 + KPID.y*SpeedErrorAccu + KPID.z*(SpeedErrorT0-SpeedErrorHis1T0);
						cout<<"The Torque Increment "<<TorqueIncrement<<endl;
						SpeedErrorHis2T0 = SpeedErrorHis1T0;
						SpeedErrorHis1T0 = SpeedErrorT0;
					}else{
						if (SpeedType == 1)
						{
							// If the function is configured to calculate linar speed for a wheel but no radiu has been specified
							// return false and end the function
							if (Radius == 0)
							{
								cout<<"Wrong radius input when calculating linear speed of a wheel."<<endl;
								return false;
							}else{

							}
						}else{
							if (SpeedType == 2)
							{
								/* code */
							}else{
								cout<<"Wrong Speed Type."<<endl;
								return false;
							}
						}
					}

					TotalTorque += TorqueIncrement;
					cout<<"TotalTorque = "<<TotalTorque<<endl;
					double TotalTorqueRef;
					TotalTorqueRef = JointNTBC->GetForce(AxisIndex) + TorqueIncrement;
					cout<<"TotalTorqueRef = "<<TotalTorqueRef<<endl;
					JointNTBC->SetForce(AxisIndex,(JointNTBC->GetForce(AxisIndex) + TorqueIncrement));
					return true;
				}
		// This public function is used to calculate the angular velocity of a revolute joint
		// This method is only valid in simulation
		public: double RevolutionSpeedCal(physics::JointPtr JointNTBC, const int AxisIndex)
				{
					double ResSpeedRef;

					// In the API instruction, fucntion GetVelocity() returns the "rotation rate"
					// The unit of this rotation rate is "rad/s"
					ResSpeedRef = JointNTBC->GetVelocity(AxisIndex);
					//cout<<"ResSpeedRef = "<<ResSpeedRef<<" rad/s"<<endl;

					return ResSpeedRef;
				}
		// This function is an old version function of RevolutionSpeedCal()
		// Which has the same functionality as RevolutionSpeedCal()
		private: double RevolutionSpeedCalOld(physics::JointPtr JointNTBC, const int AxisIndex)
				{
					math::Angle CurrentAngle;
					double CurrentAngleRadVal;
					static double CurrentAngleRadValHis = 0;
					common::Time TimeTmp;
					physics::JointState CurrentJointState(JointNTBC);
					double TimeStampNow;
					static double TimeStampNowHis = 0;
					double RevSpeed;

					CurrentAngle = JointNTBC->GetAngle(AxisIndex);
					CurrentAngleRadVal = CurrentAngle.Radian();

					TimeTmp = CurrentJointState.GetSimTime();
					TimeStampNow = TimeTmp.Double();

					// This method uses the change of the angle divided by the time interval
					RevSpeed = (CurrentAngleRadVal-CurrentAngleRadValHis)/(TimeStampNow-TimeStampNowHis); // The unit is rad/sec

					CurrentAngleRadValHis = CurrentAngleRadVal;
					TimeStampNowHis = TimeStampNow;

					return RevSpeed;
				}
		// A complementary filter
		// The default coefficient of the filter is 0.9
		public: double ComplementaryFilter(double FilteringValue, double ComplementFilterPar = 0.9)
				{
					static double ValueRecorder = 0;
					double FiltedValue;
					FiltedValue = (1 - ComplementFilterPar)*FilteringValue + ComplementFilterPar*ValueRecorder;

					ValueRecorder = FiltedValue;

					return FiltedValue;
				}

		// Current Model Pointer
		private: physics::ModelPtr model;
		// Pointers to all the Joints the current model has
		private: physics::JointPtr JointWR;
		private: physics::JointPtr JointWL;
		private: physics::JointPtr JointWF;
		private: physics::JointPtr JointCB;
		// The event that will be refreshed in every iteration of the simulation
		private: event::ConnectionPtr updateConnection;
		// Default PID controller
		public:  math::Vector3 DefaultKPID;	// First digit is Kp, second digit is Ki and third digit is Kd
		//################# Variables for testing ############################
		// In the future version, this radius value will be eliminate
		private: double WheelRadius;

		//####################################################################
	};

	GZ_REGISTER_MODEL_PLUGIN(ModelController1)
}<commit_msg>Clear up my code a little bit, adapt a new structure for this model controller<commit_after>#include <boost/bind.hpp>
#include <gazebo/gazebo.hh>
#include <gazebo/physics/physics.hh>
#include <gazebo/common/common.hh>
#include <iostream>
#include <cmath>
using namespace std;

#define PI 3.1415926

namespace gazebo
{
	class ModelController1 : public ModelPlugin
	{
		public: ModelController1() : ModelPlugin(),DefaultKPID(0.01,0,0)
				{
					// Initialize variables
					WheelRadius =  0.045275;
					// A hint of model been initialized
					printf("Model Initiated\n");
				}
		public: void Load (physics::ModelPtr _parent, sdf::ElementPtr _sdf)
				{
					// Initialize the whole system
					SystemInitialization(_parent);
					// Testing codes
					this->JointWR->SetVelocity(0,0);
					this->JointWL->SetVelocity(0,0);
					math::Angle AngleInterested(0.5235987);
					this->JointCB->SetAngle(0,AngleInterested);
					// Event register, which will make the function be executed in each iteration
					this->updateConnection = event::Events::ConnectWorldUpdateBegin(boost::bind(&ModelController1::OnSystemRunning, this, _1));
				}
		private: void SystemInitialization(physics::ModelPtr parentModel)
				{
					// Get all the pointers point to right objects
					this->model = parentModel;
					this->JointWR = model->GetJoint("Right_wheel_hinge");
					this->JointWL = model->GetJoint("Left_wheel_hinge");
					this->JointWF = model->GetJoint("Front_wheel_hinge");
					this->JointCB = model->GetJoint("Center_hinge");
					// Setting the model states
					// Setting the maximium torque of the two wheels
					this->JointWR->SetMaxForce(0,1000);
					this->JointWL->SetMaxForce(0,1000);
					// Setting the maximium torque of the front wheel
					this->JointWF->SetMaxForce(0,1000);
					// Setting the maximium torque of the body bending joint
					this->JointCB->SetMaxForce(0,1000);
					// Set the angle of the hinge in the center to zero
					math::Angle InitialAngle(0);
					this->JointCB->SetAngle(0, InitialAngle);
				}
		// Testing function
		private: void OnSystemRunning(const common::UpdateInfo & /*_info*/)
				{
					double AngleValue;
					double force;
					force = JointCB->GetForce(0);
					cout<<"The Angle of the bending:"<<force<<endl;
					AngleValue = this->RevolutionSpeedCal(JointWR,0);
					cout<<"The real rotation rate is "<<AngleValue<<" rad/s"<<endl;

				}
		// The unit of the angle is radian
		// In the future, this function should be defined as virtual
		public: void SetJointAngle(physics::JointPtr CurrentJoint, int RotAxis, math::Angle AngleDesired)
				{
					CurrentJoint->SetAngle(RotAxis, AngleDesired);
				}
		// This function will set the rotation rate of the joint
		// The unit of this speed is rad/s
		// In the future, this function should be defined as virtual
		public: void SetJointSpeed(physics::JointPtr CurrentJoint, int RotAxis, double SpeedDesired)
				{
					CurrentJoint->SetVelocity(RotAxis,SpeedDesired);
				}
		// This public function is used to calculate the angular velocity of a revolute joint
		// In the future, this function should be defined as virtual
		public: double RevolutionSpeedCal(physics::JointPtr JointNTBC, const int AxisIndex)
				{
					double ResSpeedRef;

					// In the API instruction, fucntion GetVelocity() returns the "rotation rate"
					// The unit of this rotation rate is "rad/s"
					ResSpeedRef = JointNTBC->GetVelocity(AxisIndex);
					//cout<<"ResSpeedRef = "<<ResSpeedRef<<" rad/s"<<endl;

					return ResSpeedRef;
				}
		// This function is an old version function of RevolutionSpeedCal()
		// Which has the same functionality as RevolutionSpeedCal()
		private: double RevolutionSpeedCalOld(physics::JointPtr JointNTBC, const int AxisIndex)
				{
					math::Angle CurrentAngle;
					double CurrentAngleRadVal;
					static double CurrentAngleRadValHis = 0;
					common::Time TimeTmp;
					physics::JointState CurrentJointState(JointNTBC);
					double TimeStampNow;
					static double TimeStampNowHis = 0;
					double RevSpeed;

					CurrentAngle = JointNTBC->GetAngle(AxisIndex);
					CurrentAngleRadVal = CurrentAngle.Radian();

					TimeTmp = CurrentJointState.GetSimTime();
					TimeStampNow = TimeTmp.Double();

					// This method uses the change of the angle divided by the time interval
					RevSpeed = (CurrentAngleRadVal-CurrentAngleRadValHis)/(TimeStampNow-TimeStampNowHis); // The unit is rad/sec

					CurrentAngleRadValHis = CurrentAngleRadVal;
					TimeStampNowHis = TimeStampNow;

					return RevSpeed;
				}
		// Angle calculation base on the two points
		// This angle is in the static global frame
		private: math::Angle AngleCalculation2Points(math::Vector2d StartPoint, math::Vector2d EndPoint)
				{
					double displacementX, displacementY, angleC;
					displacementX = EndPoint.x - StartPoint.x;
					displacementY = EndPoint.y - EndPoint.y;
					angleC = atan2(displacementY,displacementX);
					math::Angle ReturnAngle(angleC);
					return ReturnAngle;
				}
		// Angle PID Controller
		// DesiredAngleis in the static global frame
		// CurrentSpeed is the rotation rate of the wheel
		private: void AnglePIDController(math::Angle DesiredAngle, math::Angle CurrentAngle, math::Vector2d CurrentSpeed)
				{

				}
		// A complementary filter
		// The default coefficient of the filter is 0.9
		public: double ComplementaryFilter(double FilteringValue, double ComplementFilterPar = 0.9)
				{
					static double ValueRecorder = 0;
					double FiltedValue;
					FiltedValue = (1 - ComplementFilterPar)*FilteringValue + ComplementFilterPar*ValueRecorder;

					ValueRecorder = FiltedValue;

					return FiltedValue;
				}

		// Current Model Pointer
		private: physics::ModelPtr model;
		// Pointers to all the Joints the current model has
		private: physics::JointPtr JointWR;
		private: physics::JointPtr JointWL;
		private: physics::JointPtr JointWF;
		private: physics::JointPtr JointCB;
		// The event that will be refreshed in every iteration of the simulation
		private: event::ConnectionPtr updateConnection;
		// Default PID controller
		public:  math::Vector3 DefaultKPID;	// First digit is Kp, second digit is Ki and third digit is Kd
		//################# Variables for testing ############################
		// In the future version, this radius value will be eliminate
		private: double WheelRadius;

		//####################################################################
	};

	GZ_REGISTER_MODEL_PLUGIN(ModelController1)
}<|endoftext|>


<commit_before>#include "NFComm/NFPluginModule/NFPlatform.h"

#if NF_PLATFORM == NF_PLATFORM_WIN
#endif

#pragma comment( lib, "Dbghelp.lib" )

#ifdef NF_DEBUG_MODE

#if NF_PLATFORM == NF_PLATFORM_WIN

#ifdef NF_DYNAMIC_PLUGIN
#pragma comment( lib, "NFCore_d.lib" )
#pragma comment( lib, "Theron_d.lib" )

#else
#pragma comment( lib, "NFCore_d.lib" )
#pragma comment( lib, "Theron_d.lib" )
#endif

//#pragma comment( lib, "Theron_d.lib" )
#pragma comment( lib, "libglog_static_d.lib" )
#elif NF_PLATFORM == NF_PLATFORM_LINUX || NF_PLATFORM == NF_PLATFORM_ANDROID
#pragma comment( lib, "NFCore_d.a" )
#pragma comment( lib, "libglog_d.a" )
#pragma comment( lib, "libtherond.a")
#elif NF_PLATFORM == NF_PLATFORM_APPLE || NF_PLATFORM == NF_PLATFORM_APPLE_IOS
#endif

#else

#if NF_PLATFORM == NF_PLATFORM_WIN
#ifdef NF_DYNAMIC_PLUGIN
#pragma comment( lib, "NFCore.lib" )
#pragma comment( lib, "Theron.lib" )
#else
#pragma comment( lib, "NFCorec.lib" )
#pragma comment( lib, "Theron.lib" )
#endif

//#pragma comment( lib, "Theron.lib" )
#pragma comment( lib, "libglog_static.lib" )
#elif NF_PLATFORM == NF_PLATFORM_LINUX || NF_PLATFORM == NF_PLATFORM_ANDROID
#pragma comment( lib, "NFCore.a" )
#pragma comment( lib, "libglog.a" )
#pragma comment( lib, "libtherond.a")
#elif NF_PLATFORM == NF_PLATFORM_APPLE || NF_PLATFORM == NF_PLATFORM_APPLE_IOS
#endif

#endif
<commit_msg>Modify complile error of NFLogPlugin<commit_after>#include "NFComm/NFPluginModule/NFPlatform.h"

#if NF_PLATFORM == NF_PLATFORM_WIN
#endif

#pragma comment( lib, "Dbghelp.lib" )

#ifdef NF_DEBUG_MODE

#if NF_PLATFORM == NF_PLATFORM_WIN

#ifdef NF_DYNAMIC_PLUGIN
#pragma comment( lib, "NFCore_d.lib" )
#pragma comment( lib, "Theron_d.lib" )

#else
#pragma comment( lib, "NFCore_d.lib" )
#pragma comment( lib, "Theron_d.lib" )
#endif

//#pragma comment( lib, "Theron_d.lib" )
//#pragma comment( lib, "libglog_static_d.lib" )
#elif NF_PLATFORM == NF_PLATFORM_LINUX || NF_PLATFORM == NF_PLATFORM_ANDROID
#pragma comment( lib, "NFCore_d.a" )
#pragma comment( lib, "libglog_d.a" )
#pragma comment( lib, "libtherond.a")
#elif NF_PLATFORM == NF_PLATFORM_APPLE || NF_PLATFORM == NF_PLATFORM_APPLE_IOS
#endif

#else

#if NF_PLATFORM == NF_PLATFORM_WIN
#ifdef NF_DYNAMIC_PLUGIN
#pragma comment( lib, "NFCore.lib" )
#pragma comment( lib, "Theron.lib" )
#else
#pragma comment( lib, "NFCorec.lib" )
#pragma comment( lib, "Theron.lib" )
#endif

//#pragma comment( lib, "Theron.lib" )
#pragma comment( lib, "libglog_static.lib" )
#elif NF_PLATFORM == NF_PLATFORM_LINUX || NF_PLATFORM == NF_PLATFORM_ANDROID
#pragma comment( lib, "NFCore.a" )
#pragma comment( lib, "libglog.a" )
#pragma comment( lib, "libtherond.a")
#elif NF_PLATFORM == NF_PLATFORM_APPLE || NF_PLATFORM == NF_PLATFORM_APPLE_IOS
#endif

#endif
<|endoftext|>


<commit_before>/*

 Copyright (c) 2013, Ford Motor Company
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the Ford Motor Company nor the names of its contributors
 may be used to endorse or promote products derived from this software
 without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "application_manager/commands/mobile/register_app_interface_response.h"
#include "interfaces/MOBILE_API.h"
#include "application_manager/policies/policy_handler.h"
#include "application_manager/application_manager_impl.h"
#include "connection_handler/connection_handler.h"

namespace application_manager {

namespace commands {

void RegisterAppInterfaceResponse::Run() {
  LOG4CXX_AUTO_TRACE(logger_);

  mobile_apis::Result::eType result_code = mobile_apis::Result::INVALID_ENUM;
  bool success = (*message_)[strings::msg_params][strings::success].asBool();
  bool last_message = !success;
  // Do not close connection in case of APPLICATION_NOT_REGISTERED despite it is an error
  if (!success && (*message_)[strings::msg_params].keyExists(strings::result_code)) {
    result_code = static_cast<mobile_apis::Result::eType>(
        (*message_)[strings::msg_params][strings::result_code].asInt());
    if (result_code ==  mobile_apis::Result::APPLICATION_REGISTERED_ALREADY) {
      last_message = false;
    }
  }

  SendResponse(success, result_code, last_message);

  // Add registered application to the policy db right after response sent to
  // mobile to be able to check all other API according to app permissions
  uint32_t connection_key =
      (*message_)[strings::params][strings::connection_key].asUInt();
  application_manager::ApplicationConstSharedPtr app =
      application_manager::ApplicationManagerImpl::instance()->
      application(connection_key);
  if (app.valid()) {
    policy::PolicyHandler *policy_handler = policy::PolicyHandler::instance();
    std::string mobile_app_id = app->mobile_app_id();
    policy_handler->OnAppRegisteredOnMobile(mobile_app_id);
    SetHeartBeatTimeout(connection_key, mobile_app_id);
  }
}

void RegisterAppInterfaceResponse::SetHeartBeatTimeout(
    uint32_t connection_key, const std::string& mobile_app_id) {
  LOG4CXX_AUTO_TRACE(logger_);
  policy::PolicyHandler *policy_handler = policy::PolicyHandler::instance();
  if (policy_handler->PolicyEnabled()) {
    const int32_t timeout = policy_handler->HeartBeatTimeout(mobile_app_id) /
        date_time::DateTime::MILLISECONDS_IN_SECOND;
    if (timeout > 0) {
      application_manager::ApplicationManagerImpl::instance()->
          connection_handler()->SetHeartBeatTimeout(connection_key, timeout);
    }
  } else {
    LOG4CXX_INFO(logger_, "Policy is turn off");
  }
}

}  // namespace commands
}  // namespace application_manager
<commit_msg>Avoid PROTOCOL_VIOLATION during streaming process<commit_after>/*

 Copyright (c) 2013, Ford Motor Company
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the Ford Motor Company nor the names of its contributors
 may be used to endorse or promote products derived from this software
 without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "application_manager/commands/mobile/register_app_interface_response.h"
#include "interfaces/MOBILE_API.h"
#include "application_manager/policies/policy_handler.h"
#include "application_manager/application_manager_impl.h"
#include "connection_handler/connection_handler.h"

namespace application_manager {

namespace commands {

void RegisterAppInterfaceResponse::Run() {
  LOG4CXX_AUTO_TRACE(logger_);

  mobile_apis::Result::eType result_code = mobile_apis::Result::INVALID_ENUM;
  bool success = (*message_)[strings::msg_params][strings::success].asBool();
  bool last_message = !success;
  // Do not close connection in case of APPLICATION_NOT_REGISTERED despite it is an error
  if (!success && (*message_)[strings::msg_params].keyExists(strings::result_code)) {
    result_code = static_cast<mobile_apis::Result::eType>(
        (*message_)[strings::msg_params][strings::result_code].asInt());
    if (result_code ==  mobile_apis::Result::APPLICATION_REGISTERED_ALREADY) {
      last_message = false;
    }
  }

  SendResponse(success, result_code, last_message);

  if (mobile_apis::Result::SUCCESS != result_code) { return; }

  // Add registered application to the policy db right after response sent to
  // mobile to be able to check all other API according to app permissions
  uint32_t connection_key =
      (*message_)[strings::params][strings::connection_key].asUInt();
  application_manager::ApplicationConstSharedPtr app =
      application_manager::ApplicationManagerImpl::instance()->
      application(connection_key);
  if (app.valid()) {
    policy::PolicyHandler *policy_handler = policy::PolicyHandler::instance();
    std::string mobile_app_id = app->mobile_app_id();
    policy_handler->OnAppRegisteredOnMobile(mobile_app_id);
    SetHeartBeatTimeout(connection_key, mobile_app_id);
  }
}

void RegisterAppInterfaceResponse::SetHeartBeatTimeout(
    uint32_t connection_key, const std::string& mobile_app_id) {
  LOG4CXX_AUTO_TRACE(logger_);
  policy::PolicyHandler *policy_handler = policy::PolicyHandler::instance();
  if (policy_handler->PolicyEnabled()) {
    const int32_t timeout = policy_handler->HeartBeatTimeout(mobile_app_id) /
        date_time::DateTime::MILLISECONDS_IN_SECOND;
    if (timeout > 0) {
      application_manager::ApplicationManagerImpl::instance()->
          connection_handler()->SetHeartBeatTimeout(connection_key, timeout);
    }
  } else {
    LOG4CXX_INFO(logger_, "Policy is turn off");
  }
}

}  // namespace commands
}  // namespace application_manager
<|endoftext|>


<commit_before>#include <QApplication>
#include <QtGlobal>
#include <QProcess>
#include <QFile>
#include <QCommandLineParser>
#include "neovimconnector.h"
#include "app.h"

#if defined(Q_OS_WIN) && defined(USE_STATIC_QT)
#include <QtPlugin>
Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin);
#endif

int ui_main(int argc, char **argv)
{
	NeovimQt::App app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	int timeout = parser.value("timeout").toInt();
	auto c = app.createConnector(parser);
	c->setRequestTimeout(timeout);
	app.showUi(c, parser);
	return app.exec();
}

int cli_main(int argc, char **argv)
{
	QCoreApplication app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	QStringList new_args = app.arguments().mid(1);
	new_args.insert(0, "--nofork");
	if (QProcess::startDetached(app.applicationFilePath(), new_args)) {
		return 0;
	} else {
		qWarning() << "Unable to fork into background";
		return -1;
	}
}

int main(int argc, char **argv)
{
#if defined (Q_OS_UNIX) && ! defined (Q_OS_MAC)
	// Do an early check for --nofork. We need to do this here, before
	// creating a QApplication, since QCommandLineParser requires one
	bool nofork = false;
	for (int i=1; i<argc; i++) {
		if (QString::compare("--", argv[i]) == 0) {
			break;
		} else if (QString::compare("--spawn", argv[i]) == 0) {
			break;
		} else if (QString::compare("--embed", argv[i]) == 0) {
			// Due to https://github.com/equalsraf/neovim-qt/issues/276 --embed
			// implies --nofork
			nofork = true;
		} else if (QString::compare("--nofork", argv[i]) == 0) {
			nofork = true;
		}
	}

	if (nofork) {
		return ui_main(argc, argv);
	} else {
		return cli_main(argc, argv);
	}
#else
	return ui_main(argc, argv);
#endif
}

<commit_msg>Windows: Enable HiDpi scalling<commit_after>#include <QApplication>
#include <QtGlobal>
#include <QProcess>
#include <QFile>
#include <QCommandLineParser>
#include "neovimconnector.h"
#include "app.h"

#if defined(Q_OS_WIN) && defined(USE_STATIC_QT)
#include <QtPlugin>
Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin);
#endif

int ui_main(int argc, char **argv)
{

#ifdef Q_OS_WIN
	// Enables automatic high-DPI scaling
	// https://github.com/equalsraf/neovim-qt/issues/391
	//
	// The other way to do this is to set Qt::AA_EnableHighDpiScaling
	// but it does not seem to work on Windows.
	//
	// @equalsraf: For now I'm setting this in windows only, there open
	// issues in upstream Qt that suggests this may have unexpected effects
	// in other systems (QTBUG-65061, QTBUG-65102), also QTBUG-63580 offers
	// contradictory information with what we have experienced.
	qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
#endif

	NeovimQt::App app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	int timeout = parser.value("timeout").toInt();
	auto c = app.createConnector(parser);
	c->setRequestTimeout(timeout);
	app.showUi(c, parser);
	return app.exec();
}

int cli_main(int argc, char **argv)
{
	QCoreApplication app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	QStringList new_args = app.arguments().mid(1);
	new_args.insert(0, "--nofork");
	if (QProcess::startDetached(app.applicationFilePath(), new_args)) {
		return 0;
	} else {
		qWarning() << "Unable to fork into background";
		return -1;
	}
}

int main(int argc, char **argv)
{
#if defined (Q_OS_UNIX) && ! defined (Q_OS_MAC)
	// Do an early check for --nofork. We need to do this here, before
	// creating a QApplication, since QCommandLineParser requires one
	bool nofork = false;
	for (int i=1; i<argc; i++) {
		if (QString::compare("--", argv[i]) == 0) {
			break;
		} else if (QString::compare("--spawn", argv[i]) == 0) {
			break;
		} else if (QString::compare("--embed", argv[i]) == 0) {
			// Due to https://github.com/equalsraf/neovim-qt/issues/276 --embed
			// implies --nofork
			nofork = true;
		} else if (QString::compare("--nofork", argv[i]) == 0) {
			nofork = true;
		}
	}

	if (nofork) {
		return ui_main(argc, argv);
	} else {
		return cli_main(argc, argv);
	}
#else
	return ui_main(argc, argv);
#endif
}

<|endoftext|>


<commit_before>#include <QApplication>
#include <QtGlobal>
#include <QProcess>
#include <QFile>
#include <QCommandLineParser>
#include "neovimconnector.h"
#include "app.h"

#if defined(Q_OS_WIN) && defined(USE_STATIC_QT)
#include <QtPlugin>
Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin);
#endif

int ui_main(int argc, char **argv)
{
	NeovimQt::App app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	int timeout = parser.value("timeout").toInt();
	auto c = app.createConnector(parser);
	c->setRequestTimeout(timeout);
	app.showUi(c, parser);
	return app.exec();
}

int cli_main(int argc, char **argv)
{
	QCoreApplication app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	QStringList new_args = app.arguments().mid(1);
	new_args.insert(0, "--nofork");
	if (QProcess::startDetached(app.applicationFilePath(), new_args)) {
		return 0;
	} else {
		qWarning() << "Unable to fork into background";
		return -1;
	}
}

int main(int argc, char **argv)
{
#if defined (Q_OS_UNIX) && ! defined (Q_OS_MAC)
	// Do an early check for --nofork. We need to do this here, before
	// creating a QApplication, since QCommandLineParser requires one
	bool nofork = false;
	for (int i=1; i<argc; i++) {
		if (QString::compare("--", argv[i]) == 0) {
			break;
		} else if (QString::compare("--spawn", argv[i]) == 0) {
			break;
		} else if (QString::compare("--nofork", argv[i]) == 0) {
			nofork = true;
		}
	}

	if (nofork) {
		return ui_main(argc, argv);
	} else {
		return cli_main(argc, argv);
	}
#else
	return ui_main(argc, argv);
#endif
}

<commit_msg>Option --embed implies --nofork<commit_after>#include <QApplication>
#include <QtGlobal>
#include <QProcess>
#include <QFile>
#include <QCommandLineParser>
#include "neovimconnector.h"
#include "app.h"

#if defined(Q_OS_WIN) && defined(USE_STATIC_QT)
#include <QtPlugin>
Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin);
#endif

int ui_main(int argc, char **argv)
{
	NeovimQt::App app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	int timeout = parser.value("timeout").toInt();
	auto c = app.createConnector(parser);
	c->setRequestTimeout(timeout);
	app.showUi(c, parser);
	return app.exec();
}

int cli_main(int argc, char **argv)
{
	QCoreApplication app(argc, argv);

	QCommandLineParser parser;
	NeovimQt::App::processCliOptions(parser, app.arguments());

	QStringList new_args = app.arguments().mid(1);
	new_args.insert(0, "--nofork");
	if (QProcess::startDetached(app.applicationFilePath(), new_args)) {
		return 0;
	} else {
		qWarning() << "Unable to fork into background";
		return -1;
	}
}

int main(int argc, char **argv)
{
#if defined (Q_OS_UNIX) && ! defined (Q_OS_MAC)
	// Do an early check for --nofork. We need to do this here, before
	// creating a QApplication, since QCommandLineParser requires one
	bool nofork = false;
	for (int i=1; i<argc; i++) {
		if (QString::compare("--", argv[i]) == 0) {
			break;
		} else if (QString::compare("--spawn", argv[i]) == 0) {
			break;
		} else if (QString::compare("--embed", argv[i]) == 0) {
			// Due to https://github.com/equalsraf/neovim-qt/issues/276 --embed
			// implies --nofork
			nofork = true;
		} else if (QString::compare("--nofork", argv[i]) == 0) {
			nofork = true;
		}
	}

	if (nofork) {
		return ui_main(argc, argv);
	} else {
		return cli_main(argc, argv);
	}
#else
	return ui_main(argc, argv);
#endif
}

<|endoftext|>


<commit_before>#include <QApplication>
#include <QFontDatabase>
#include <QtGlobal>
#include <QFile>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QDir>
#include "neovimconnector.h"
#include "mainwindow.h"

/// A log handler for Qt messages, all messages are dumped into the file
/// passed via the NVIM_QT_LOG variable. Some information is only available
/// in debug builds (e.g. qDebug is only called in debug builds).
///
/// In UNIX Qt prints messages to the console output, but in Windows this is
/// the only way to get Qt's debug/warning messages.
void logger(QtMsgType type, const QMessageLogContext& ctx, const QString& msg)
{
	QFile logFile(qgetenv("NVIM_QT_LOG"));
	if (logFile.open(QIODevice::Append | QIODevice::Text)) {
		QTextStream stream(&logFile);
		stream << msg << "\n";
	}
}

int main(int argc, char **argv)
{
	QApplication app(argc, argv);
	app.setApplicationDisplayName("Neovim");
	app.setWindowIcon(QIcon(":/neovim.png"));

	if (!qgetenv("NVIM_QT_LOG").isEmpty()) {
		qInstallMessageHandler(logger);
	}

	QCommandLineParser parser;
	parser.addOption(QCommandLineOption("embed",
		QCoreApplication::translate("main", "Communicate with Neovim over stdin/out")));
	parser.addOption(QCommandLineOption("server",
		QCoreApplication::translate("main", "Connect to existing Neovim instance"),
		QCoreApplication::translate("main", "addr")));
	parser.addOption(QCommandLineOption("geometry",
		QCoreApplication::translate("main", "Initial window geometry"),
		QCoreApplication::translate("main", "geometry")));
	parser.addOption(QCommandLineOption("maximized",
		QCoreApplication::translate("main", "Maximize the window on startup")));
	parser.addOption(QCommandLineOption("fullscreen",
		QCoreApplication::translate("main", "Open the window in fullscreen on startup")));
	parser.addPositionalArgument("...", "Additional arguments are fowarded to Neovim", "[-- ...]");
	parser.addHelpOption();

	int sep = app.arguments().indexOf("--");
	QStringList neovimArgs;
	if (sep != -1) {
		QStringList args = app.arguments().mid(0, sep);
		neovimArgs += app.arguments().mid(sep+1);
		parser.process(app.arguments());
	} else {
		parser.process(app.arguments());
	}

	if (parser.isSet("help")) {
		parser.showHelp();
	}

	NeovimQt::NeovimConnector *c;
	if (parser.isSet("embed")) {
		c = NeovimQt::NeovimConnector::fromStdinOut();
	} else {
		if (parser.isSet("server")) {
			QString server = parser.value("server");
			c = NeovimQt::NeovimConnector::connectToNeovim(server);
		} else {
#ifdef NVIM_QT_RUNTIME_PATH
			if (QFileInfo(NVIM_QT_RUNTIME_PATH).isDir()) {
				neovimArgs.insert(0, "--cmd");
				neovimArgs.insert(1, QString("set rtp+=%1")
						.arg(NVIM_QT_RUNTIME_PATH));
			} else {
				QDir d = QFileInfo(QCoreApplication::applicationDirPath()).dir();
				d.cd("share");
				d.cd("nvim-qt");
				d.cd("runtime");

				if (d.exists()) {
					neovimArgs.insert(0, "--cmd");
					neovimArgs.insert(1, QString("set rtp+=%1")
							.arg(d.path()));
				}
			}
#endif
			c = NeovimQt::NeovimConnector::spawn(neovimArgs);
		}
	}

#ifdef NEOVIMQT_GUI_WIDGET
	NeovimQt::Shell *win = new NeovimQt::Shell(c);
	win->show();
	if (parser.isSet("fullscreen")) {
		win->showFullScreen();
	} else if (parser.isSet("maximized")) {
		win->showMaximized();
	} else {
		win->show();
	}
#else
	NeovimQt::MainWindow *win = new NeovimQt::MainWindow(c);
	if (parser.isSet("fullscreen")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::FullScreen);
	} else if (parser.isSet("maximized")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::Maximized);
	} else {
		win->delayedShow();
	}
#endif
	return app.exec();
}

<commit_msg>Always search for relative runtime path<commit_after>#include <QApplication>
#include <QFontDatabase>
#include <QtGlobal>
#include <QFile>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QDir>
#include "neovimconnector.h"
#include "mainwindow.h"

/// A log handler for Qt messages, all messages are dumped into the file
/// passed via the NVIM_QT_LOG variable. Some information is only available
/// in debug builds (e.g. qDebug is only called in debug builds).
///
/// In UNIX Qt prints messages to the console output, but in Windows this is
/// the only way to get Qt's debug/warning messages.
void logger(QtMsgType type, const QMessageLogContext& ctx, const QString& msg)
{
	QFile logFile(qgetenv("NVIM_QT_LOG"));
	if (logFile.open(QIODevice::Append | QIODevice::Text)) {
		QTextStream stream(&logFile);
		stream << msg << "\n";
	}
}

int main(int argc, char **argv)
{
	QApplication app(argc, argv);
	app.setApplicationDisplayName("Neovim");
	app.setWindowIcon(QIcon(":/neovim.png"));

	if (!qgetenv("NVIM_QT_LOG").isEmpty()) {
		qInstallMessageHandler(logger);
	}

	QCommandLineParser parser;
	parser.addOption(QCommandLineOption("embed",
		QCoreApplication::translate("main", "Communicate with Neovim over stdin/out")));
	parser.addOption(QCommandLineOption("server",
		QCoreApplication::translate("main", "Connect to existing Neovim instance"),
		QCoreApplication::translate("main", "addr")));
	parser.addOption(QCommandLineOption("geometry",
		QCoreApplication::translate("main", "Initial window geometry"),
		QCoreApplication::translate("main", "geometry")));
	parser.addOption(QCommandLineOption("maximized",
		QCoreApplication::translate("main", "Maximize the window on startup")));
	parser.addOption(QCommandLineOption("fullscreen",
		QCoreApplication::translate("main", "Open the window in fullscreen on startup")));
	parser.addPositionalArgument("...", "Additional arguments are fowarded to Neovim", "[-- ...]");
	parser.addHelpOption();

	int sep = app.arguments().indexOf("--");
	QStringList neovimArgs;
	if (sep != -1) {
		QStringList args = app.arguments().mid(0, sep);
		neovimArgs += app.arguments().mid(sep+1);
		parser.process(app.arguments());
	} else {
		parser.process(app.arguments());
	}

	if (parser.isSet("help")) {
		parser.showHelp();
	}

	NeovimQt::NeovimConnector *c;
	if (parser.isSet("embed")) {
		c = NeovimQt::NeovimConnector::fromStdinOut();
	} else {
		if (parser.isSet("server")) {
			QString server = parser.value("server");
			c = NeovimQt::NeovimConnector::connectToNeovim(server);
		} else {
#ifdef NVIM_QT_RUNTIME_PATH
			if (QFileInfo(NVIM_QT_RUNTIME_PATH).isDir()) {
				neovimArgs.insert(0, "--cmd");
				neovimArgs.insert(1, QString("set rtp+=%1")
						.arg(NVIM_QT_RUNTIME_PATH));
			} else
#endif
			{
				QDir d = QFileInfo(QCoreApplication::applicationDirPath()).dir();
				d.cd("share");
				d.cd("nvim-qt");
				d.cd("runtime");

				if (d.exists()) {
					neovimArgs.insert(0, "--cmd");
					neovimArgs.insert(1, QString("set rtp+=%1")
							.arg(d.path()));
				}
			}
			c = NeovimQt::NeovimConnector::spawn(neovimArgs);
		}
	}

#ifdef NEOVIMQT_GUI_WIDGET
	NeovimQt::Shell *win = new NeovimQt::Shell(c);
	win->show();
	if (parser.isSet("fullscreen")) {
		win->showFullScreen();
	} else if (parser.isSet("maximized")) {
		win->showMaximized();
	} else {
		win->show();
	}
#else
	NeovimQt::MainWindow *win = new NeovimQt::MainWindow(c);
	if (parser.isSet("fullscreen")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::FullScreen);
	} else if (parser.isSet("maximized")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::Maximized);
	} else {
		win->delayedShow();
	}
#endif
	return app.exec();
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include "node_connection.h"
#include "node_request.h"
#include <iostream>
#include <memory>
#include <mutex>
#include <atomic>

namespace arangodb { namespace fuerte { namespace js {

///////////////////////////////////////////////////////////////////////////////
// NConnectionBuilder /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NAN_METHOD(NConnectionBuilder::New) {
  if (info.IsConstructCall()) {
      NConnectionBuilder* obj = new NConnectionBuilder();
      obj->Wrap(info.This());
      info.GetReturnValue().Set(info.This());
  } else {
    v8::Local<v8::Function> builder = Nan::New(constructor());
    info.GetReturnValue().Set(Nan::NewInstance(builder).ToLocalChecked());
 }
}

NAN_METHOD(NConnectionBuilder::connect){
  try {
    v8::Local<v8::Function> connFunction = Nan::New(NConnection::constructor());
    const int argc = 1;
    v8::Local<v8::Value> argv[argc] = {info.This()};
    auto connInstance = Nan::NewInstance(connFunction, argc, argv).ToLocalChecked();
    info.GetReturnValue().Set(connInstance);
  } catch(std::exception const& e){
    std::cerr << "## DRIVER LEVEL EXCEPTION - START ##" << std::endl;
    std::cerr << e.what() << std::endl;
    std::cerr << "## DRIVER LEVEL EXCEPTION - END   ##" << std::endl;
    Nan::ThrowError("ConnectionBuilder.connect binding failed with exception"
                    " - Make sure the server is up and running");
  }
}

NAN_METHOD(NConnectionBuilder::host){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.host(to<std::string>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    std::cerr << "## DRIVER LEVEL EXCEPTION - START ##" << std::endl;
    std::cerr << e.what() << std::endl;
    std::cerr << "## DRIVER LEVEL EXCEPTION - END   ##" << std::endl;
    std::string errorMesasge = std::string("ConnectionBuilder.host binding failed with exception: ") + e.what();
    Nan::ThrowError(errorMesasge.c_str());
  }
}

NAN_METHOD(NConnectionBuilder::async){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.async(to<bool>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    Nan::ThrowError("ConnectionBuilder.async binding failed with exception");
  }
}

NAN_METHOD(NConnectionBuilder::user){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.user(to<std::string>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    Nan::ThrowError("ConnectionBuilder.user binding failed with exception");
  }
}

NAN_METHOD(NConnectionBuilder::password){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.password(to<std::string>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    Nan::ThrowError("ConnectionBuilder.user binding failed with exception");
  }
}

///////////////////////////////////////////////////////////////////////////////
// NConnection ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NAN_METHOD(NConnection::New) {
  if (info.IsConstructCall()) {
    NConnection* obj = new NConnection();
    if(info[0]->IsObject()){ // NConnectionBuilderObject -- exact type check?
      obj->_cppClass = unwrap<NConnectionBuilder>(info[0])->_cppClass.connect();
    }
    obj->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
  } else {
    v8::Local<v8::Function> cons = Nan::New(constructor());
    info.GetReturnValue().Set(Nan::NewInstance(cons).ToLocalChecked());
 }
}

///////////////////////////////////////////////////////////////////////////////
// SendRequest ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

// When we switch to c++14 we should use UniquePersistent and move it into
// the generalized lambda caputre avoiding the locking alltogehter
static std::map<fu::MessageID
               ,std::pair<v8::Persistent<v8::Function> // error
                         ,v8::Persistent<v8::Function> // success
                         >
              > callbackMap;

static std::mutex maplock;
static std::atomic<uint64_t> jsMessageID(0);

NAN_METHOD(NConnection::sendRequest) {
  try {
    if (info.Length() != 3 ) {
      Nan::ThrowTypeError("Not 3 Arguments");
    }

    if (!info[1]->IsFunction() || !info[2]->IsFunction()){
      Nan::ThrowTypeError("Callback is not a Function");
    }

    // get isolate - has node only one context??!?!? how do they work
    // context is probably a lighter version of isolate but does not allow threads
    v8::Isolate* iso = v8::Isolate::GetCurrent();

    uint64_t id = jsMessageID.fetch_add(1);
    {
      std::lock_guard<std::mutex> lock(maplock);
      auto& callbackPair = callbackMap[id]; //create map element
      auto jsOnErr = v8::Local<v8::Function>::Cast(info[1]);
      callbackPair.first.Reset(iso, jsOnErr);

      auto jsOnSucc = v8::Local<v8::Function>::Cast(info[2]);
      callbackPair.second.Reset(iso, jsOnSucc);
    }

    fu::OnErrorCallback err = [iso,id](unsigned err
                                ,std::unique_ptr<fu::Request> creq
                                ,std::unique_ptr<fu::Response> cres)
    {
      //TODO add node exceptions to callbacks
      v8::HandleScope scope(iso);

      auto jsOnErr = v8::Local<v8::Function>();
      { //create local function and dispose persistent
        std::lock_guard<std::mutex> lock(maplock);
        auto& mapElement = callbackMap[id];
        jsOnErr = v8::Local<v8::Function>::New(iso,mapElement.first);
        mapElement.first.Reset();
        mapElement.second.Reset();
        callbackMap.erase(id);
      }

      // wrap request
      v8::Local<v8::Function> requestProto = v8::Local<v8::Function>::New(iso,NRequest::constructor());
      auto reqObj = requestProto->NewInstance(iso->GetCurrentContext()).FromMaybe(v8::Local<v8::Object>());
      unwrap<NRequest>(reqObj)->setCppClass(std::move(creq));

      // wrap response
      v8::Local<v8::Function> responseProto = v8::Local<v8::Function>::New(iso,NResponse::constructor());
      auto resObj = responseProto->NewInstance(iso->GetCurrentContext()).FromMaybe(v8::Local<v8::Object>());
      unwrap<NResponse>(resObj)->setCppClass(std::move(cres));

      // build args
      const unsigned argc = 3;
      v8::Local<v8::Value> argv[argc] = { Nan::New<v8::Integer>(err), reqObj, resObj };

      // call
      jsOnErr->Call(iso->GetCurrentContext(), jsOnErr, argc, argv);

    };

    fu::OnSuccessCallback succ = [iso,id](std::unique_ptr<fu::Request> creq
                                   ,std::unique_ptr<fu::Response> cres)
    {
      //TODO add node exceptions to callbacks
      v8::HandleScope scope(iso);

      auto jsOnSucc = v8::Local<v8::Function>();
      { // create locacl function and dispose persistent
        std::lock_guard<std::mutex> lock(maplock);
        auto& mapElement = callbackMap[id];
        //create local function
        jsOnSucc = v8::Local<v8::Function>::New(iso,callbackMap[id].second);

        //dispose map element
        mapElement.first.Reset(); // do not depend on kResetInDestructorFlag of Persistent
        mapElement.second.Reset();
        callbackMap.erase(id);
      }

      // wrap request
      //v8::Local<v8::Function> requestProto = Nan::New(NConnection::constructor()); // with Nan
      v8::Local<v8::Function> requestProto = v8::Local<v8::Function>::New(iso,NRequest::constructor());
      //auto reqObj = Nan::NewInstance(requestProto).ToLocalChecked(); // with Nan
      auto reqObj = requestProto->NewInstance(iso->GetCurrentContext()).ToLocalChecked();
      unwrap<NRequest>(reqObj)->setCppClass(std::move(creq));

      // wrap response
      v8::Local<v8::Function> responseProto = v8::Local<v8::Function>::New(iso,NResponse::constructor());
      auto resObj = responseProto->NewInstance(iso->GetCurrentContext()).ToLocalChecked();
      unwrap<NResponse>(resObj)->setCppClass(std::move(cres));

      // build args
      const unsigned argc = 2;
      v8::Local<v8::Value> argv[argc] = { reqObj, resObj };

      // call
      //jsOnSucc->Call(v8::Null(iso), argc, argv);
      jsOnSucc->Call(iso->GetCurrentContext(), jsOnSucc, argc, argv);
      //jsOnSucc->Call(iso->GetCurrentContext(), iso->GetCurrentContext()->Global(), argc, argv);

    };

    //finally invoke the c++ callback
    auto req = std::unique_ptr<fu::Request>(new fu::Request(*(unwrap<NRequest>(info[0])->_cppClass))); //copy request so the old object stays valid
    unwrapSelf<NConnection>(info)->_cppClass->sendRequest(std::move(req), err, succ);
  } catch(std::exception const& e){
    Nan::ThrowError("Connection.sendRequest binding failed with exception");
  }
}

}}}
<commit_msg>add exceptions js callbacks<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include "node_connection.h"
#include "node_request.h"
#include <iostream>
#include <memory>
#include <mutex>
#include <atomic>

namespace arangodb { namespace fuerte { namespace js {

///////////////////////////////////////////////////////////////////////////////
// NConnectionBuilder /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NAN_METHOD(NConnectionBuilder::New) {
  if (info.IsConstructCall()) {
      NConnectionBuilder* obj = new NConnectionBuilder();
      obj->Wrap(info.This());
      info.GetReturnValue().Set(info.This());
  } else {
    v8::Local<v8::Function> builder = Nan::New(constructor());
    info.GetReturnValue().Set(Nan::NewInstance(builder).ToLocalChecked());
 }
}

NAN_METHOD(NConnectionBuilder::connect){
  try {
    v8::Local<v8::Function> connFunction = Nan::New(NConnection::constructor());
    const int argc = 1;
    v8::Local<v8::Value> argv[argc] = {info.This()};
    auto connInstance = Nan::NewInstance(connFunction, argc, argv).ToLocalChecked();
    info.GetReturnValue().Set(connInstance);
  } catch(std::exception const& e){
    std::cerr << "## DRIVER LEVEL EXCEPTION - START ##" << std::endl;
    std::cerr << e.what() << std::endl;
    std::cerr << "## DRIVER LEVEL EXCEPTION - END   ##" << std::endl;
    Nan::ThrowError("ConnectionBuilder.connect binding failed with exception"
                    " - Make sure the server is up and running");
  }
}

NAN_METHOD(NConnectionBuilder::host){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.host(to<std::string>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    std::cerr << "## DRIVER LEVEL EXCEPTION - START ##" << std::endl;
    std::cerr << e.what() << std::endl;
    std::cerr << "## DRIVER LEVEL EXCEPTION - END   ##" << std::endl;
    std::string errorMesasge = std::string("ConnectionBuilder.host binding failed with exception: ") + e.what();
    Nan::ThrowError(errorMesasge.c_str());
  }
}

NAN_METHOD(NConnectionBuilder::async){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.async(to<bool>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    Nan::ThrowError("ConnectionBuilder.async binding failed with exception");
  }
}

NAN_METHOD(NConnectionBuilder::user){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.user(to<std::string>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    Nan::ThrowError("ConnectionBuilder.user binding failed with exception");
  }
}

NAN_METHOD(NConnectionBuilder::password){
  try {
    if (info.Length() != 1 ) {
      Nan::ThrowTypeError("Wrong number of Arguments");
    }
    unwrapSelf<NConnectionBuilder>(info)->_cppClass.password(to<std::string>(info[0]));
    info.GetReturnValue().Set(info.This());
  } catch(std::exception const& e){
    Nan::ThrowError("ConnectionBuilder.user binding failed with exception");
  }
}

///////////////////////////////////////////////////////////////////////////////
// NConnection ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NAN_METHOD(NConnection::New) {
  if (info.IsConstructCall()) {
    NConnection* obj = new NConnection();
    if(info[0]->IsObject()){ // NConnectionBuilderObject -- exact type check?
      obj->_cppClass = unwrap<NConnectionBuilder>(info[0])->_cppClass.connect();
    }
    obj->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
  } else {
    v8::Local<v8::Function> cons = Nan::New(constructor());
    info.GetReturnValue().Set(Nan::NewInstance(cons).ToLocalChecked());
 }
}

///////////////////////////////////////////////////////////////////////////////
// SendRequest ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

// When we switch to c++14 we should use UniquePersistent and move it into
// the generalized lambda caputre avoiding the locking alltogehter
static std::map<fu::MessageID
               ,std::pair<v8::Persistent<v8::Function> // error
                         ,v8::Persistent<v8::Function> // success
                         >
              > callbackMap;

static std::mutex maplock;
static std::atomic<uint64_t> jsMessageID(0);

NAN_METHOD(NConnection::sendRequest) {
  try {
    if (info.Length() != 3 ) {
      Nan::ThrowTypeError("Not 3 Arguments");
    }

    if (!info[1]->IsFunction() || !info[2]->IsFunction()){
      Nan::ThrowTypeError("Callback is not a Function");
    }

    // get isolate - has node only one context??!?!? how do they work
    // context is probably a lighter version of isolate but does not allow threads
    v8::Isolate* iso = v8::Isolate::GetCurrent();

    uint64_t id = jsMessageID.fetch_add(1);
    {
      std::lock_guard<std::mutex> lock(maplock);
      auto& callbackPair = callbackMap[id]; //create map element
      auto jsOnErr = v8::Local<v8::Function>::Cast(info[1]);
      callbackPair.first.Reset(iso, jsOnErr);

      auto jsOnSucc = v8::Local<v8::Function>::Cast(info[2]);
      callbackPair.second.Reset(iso, jsOnSucc);
    }

    fu::OnErrorCallback err = [iso,id](unsigned err
                                ,std::unique_ptr<fu::Request> creq
                                ,std::unique_ptr<fu::Response> cres)
    {
      try {
        v8::HandleScope scope(iso);

        auto jsOnErr = v8::Local<v8::Function>();
        { //create local function and dispose persistent
          std::lock_guard<std::mutex> lock(maplock);
          auto& mapElement = callbackMap[id];
          jsOnErr = v8::Local<v8::Function>::New(iso,mapElement.first);
          mapElement.first.Reset();
          mapElement.second.Reset();
          callbackMap.erase(id);
        }

        // wrap request
        v8::Local<v8::Function> requestProto = v8::Local<v8::Function>::New(iso,NRequest::constructor());
        auto reqObj = requestProto->NewInstance(iso->GetCurrentContext()).FromMaybe(v8::Local<v8::Object>());
        unwrap<NRequest>(reqObj)->setCppClass(std::move(creq));

        // wrap response
        v8::Local<v8::Function> responseProto = v8::Local<v8::Function>::New(iso,NResponse::constructor());
        auto resObj = responseProto->NewInstance(iso->GetCurrentContext()).FromMaybe(v8::Local<v8::Object>());
        unwrap<NResponse>(resObj)->setCppClass(std::move(cres));

        // build args
        const unsigned argc = 3;
        v8::Local<v8::Value> argv[argc] = { Nan::New<v8::Integer>(err), reqObj, resObj };

        // call
        jsOnErr->Call(iso->GetCurrentContext(), jsOnErr, argc, argv);
      } catch (std::exception const& e){
        std::string errorMesasge("Exception in success callback: ");
        errorMesasge += e.what();
        iso->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(iso,errorMesasge.c_str())));
      }
    };

    fu::OnSuccessCallback succ = [iso,id](std::unique_ptr<fu::Request> creq
                                   ,std::unique_ptr<fu::Response> cres)
    {
      try {
        //TODO add node exceptions to callbacks
        v8::HandleScope scope(iso);

        auto jsOnSucc = v8::Local<v8::Function>();
        { // create locacl function and dispose persistent
          std::lock_guard<std::mutex> lock(maplock);
          auto& mapElement = callbackMap[id];
          //create local function
          jsOnSucc = v8::Local<v8::Function>::New(iso,callbackMap[id].second);

          //dispose map element
          mapElement.first.Reset(); // do not depend on kResetInDestructorFlag of Persistent
          mapElement.second.Reset();
          callbackMap.erase(id);
        }

        // wrap request
        //v8::Local<v8::Function> requestProto = Nan::New(NConnection::constructor()); // with Nan
        v8::Local<v8::Function> requestProto = v8::Local<v8::Function>::New(iso,NRequest::constructor());
        //auto reqObj = Nan::NewInstance(requestProto).ToLocalChecked(); // with Nan
        auto reqObj = requestProto->NewInstance(iso->GetCurrentContext()).ToLocalChecked();
        unwrap<NRequest>(reqObj)->setCppClass(std::move(creq));

        // wrap response
        v8::Local<v8::Function> responseProto = v8::Local<v8::Function>::New(iso,NResponse::constructor());
        auto resObj = responseProto->NewInstance(iso->GetCurrentContext()).ToLocalChecked();
        unwrap<NResponse>(resObj)->setCppClass(std::move(cres));

        // build args
        const unsigned argc = 2;
        v8::Local<v8::Value> argv[argc] = { reqObj, resObj };

        // call
        //jsOnSucc->Call(v8::Null(iso), argc, argv);
        jsOnSucc->Call(iso->GetCurrentContext(), jsOnSucc, argc, argv);
        //jsOnSucc->Call(iso->GetCurrentContext(), iso->GetCurrentContext()->Global(), argc, argv);
      } catch (std::exception const& e){
        std::string errorMesasge("Exception in error callback: ");
        errorMesasge += e.what();
        iso->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(iso,errorMesasge.c_str())));
      }
    };

    //finally invoke the c++ callback
    auto req = std::unique_ptr<fu::Request>(new fu::Request(*(unwrap<NRequest>(info[0])->_cppClass))); //copy request so the old object stays valid
    unwrapSelf<NConnection>(info)->_cppClass->sendRequest(std::move(req), err, succ);
  } catch(std::exception const& e){
    Nan::ThrowError("Connection.sendRequest binding failed with exception");
  }
}

}}}
<|endoftext|>