text:
//  Copyright (c) 2007-2013 Hartmut Kaiser
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <hpx/hpx_fwd.hpp>
#include <hpx/exception.hpp>
#include <hpx/runtime/threads/executors/service_executor.hpp>
#include <hpx/util/bind.hpp>

#include <boost/asio/deadline_timer.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

namespace hpx { namespace threads { namespace executors { namespace detail
{
    ///////////////////////////////////////////////////////////////////////////
    service_executor::service_executor(char const* pool_name)
      : pool_(get_thread_pool(pool_name)), task_count_(0), shutdown_sem_(0)
    {
        if (!pool_) {
            HPX_THROW_EXCEPTION(bad_parameter,
                "service_executor::service_executor",
                "couldn't retrieve thread pool: " + std::string(pool_name));
        }
    }

    service_executor::~service_executor()
    {
        if (task_count_ != 0)
            shutdown_sem_.wait();
    }

    void service_executor::thread_wrapper(HPX_STD_FUNCTION<void()> const& f)
    {
        f();                          // execute the actual thread function

        if (--task_count_ == 0)
            shutdown_sem_.signal();
    }

    // Schedule the specified function for execution in this executor.
    // Depending on the subclass implementation, this may block in some
    // situations.
    void service_executor::add(BOOST_RV_REF(HPX_STD_FUNCTION<void()>) f,
        char const* desc, threads::thread_state_enum initial_state,
        bool run_now, threads::thread_stacksize stacksize, error_code& ec)
    {
        ++task_count_;

        pool_->get_io_service().post(util::bind(
            &service_executor::thread_wrapper, this, boost::move(f)));
    }

    void service_executor::add_no_count(BOOST_RV_REF(HPX_STD_FUNCTION<void()>) f)
    {
        pool_->get_io_service().post(util::bind(
            &service_executor::thread_wrapper, this, boost::move(f)));
    }

    static void delayed_add(
        boost::intrusive_ptr<service_executor> this_,
        HPX_STD_FUNCTION<void()> f,
        boost::shared_ptr<boost::asio::deadline_timer>)
    {
        this_->add_no_count(boost::move(f));
    }

    // Schedule given function for execution in this executor no sooner
    // than time abs_time. This call never blocks, and may violate
    // bounds on the executor's queue size.
    void service_executor::add_at(
        boost::posix_time::ptime const& abs_time,
        BOOST_RV_REF(HPX_STD_FUNCTION<void()>) f, char const* desc,
        threads::thread_stacksize stacksize, error_code& ec)
    {
        ++task_count_;

        boost::shared_ptr<boost::asio::deadline_timer> t(
            boost::make_shared<boost::asio::deadline_timer>(
                pool_->get_io_service(), abs_time));

        t->async_wait(util::bind(&delayed_add, this, boost::move(f), t));
    }

    // Schedule given function for execution in this executor no sooner
    // than time rel_time from now. This call never blocks, and may
    // violate bounds on the executor's queue size.
    void service_executor::add_after(
        boost::posix_time::time_duration const& rel_time,
        BOOST_RV_REF(HPX_STD_FUNCTION<void()>) f, char const* desc,
        threads::thread_stacksize stacksize, error_code& ec)
    {
        ++task_count_;

        boost::shared_ptr<boost::asio::deadline_timer> t(
            boost::make_shared<boost::asio::deadline_timer>(
                pool_->get_io_service(), rel_time));

        t->async_wait(util::bind(&delayed_add, this, boost::move(f), t));
    }

    // Return an estimate of the number of waiting tasks.
    std::size_t service_executor::num_pending_closures(error_code& ec) const
    {
        return task_count_;
    }
}}}}

max_stars_repo_name: andreasbuhr/hpx

max_issues_repo_name: andreasbuhr/hpx

max_forks_repo_name: andreasbuhr/hpx


text:
// Copyright (c) 2015-2018 Daniel Cooke
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

#include "random_forest_filter.hpp"

#include <utility>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <iostream>
#include <cassert>
#include <cmath>
#include <limits>

#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>

#include "ranger/ForestProbability.h"

#include "basics/phred.hpp"

namespace octopus { namespace csr {

RandomForestFilter::RandomForestFilter(FacetFactory facet_factory,
                                       std::vector<MeasureWrapper> measures,
                                       OutputOptions output_config,
                                       ConcurrencyPolicy threading,
                                       Path ranger_forest, Path temp_directory,
                                       boost::optional<ProgressMeter&> progress)
: DoublePassVariantCallFilter {std::move(facet_factory), std::move(measures), std::move(output_config), threading, progress}
, forest_ {std::make_unique<ranger::ForestProbability>()}
, ranger_forest_ {std::move(ranger_forest)}
, temp_dir_ {std::move(temp_directory)}
, num_records_ {0}
, data_buffer_ {}
{}

const std::string RandomForestFilter::call_qual_name_ = "RFQUAL";

boost::optional<std::string> RandomForestFilter::genotype_quality_name() const
{
    return call_qual_name_;
}

void RandomForestFilter::annotate(VcfHeader::Builder& header) const
{
    header.add_format(call_qual_name_, "1", "Float", "Empirical quality score from random forest classifier");
    header.add_filter("RF", "Random Forest filtered");
}

namespace {

template <typename T>
static void write_line(const std::vector<T>& data, std::ostream& out)
{
    std::copy(std::cbegin(data), std::prev(std::cend(data)), std::ostream_iterator<T> {out, " "});
    out << data.back() << '\n';
}

} // namespace

void RandomForestFilter::prepare_for_registration(const SampleList& samples) const
{
    std::vector<std::string> data_header {};
    data_header.reserve(measures_.size());
    for (const auto& measure : measures_) {
        data_header.push_back(measure.name());
    }
    data_header.push_back("TP");
    data_.reserve(samples.size());
    for (const auto& sample : samples) {
        auto data_path = temp_dir_;
        Path fname {"octopus_ranger_temp_forest_data_" + sample + ".dat"};
        data_path /= fname;
        data_.emplace_back(data_path.string(), data_path);
        write_line(data_header, data_.back().handle);
    }
    data_buffer_.resize(samples.size());
}

namespace {

template <typename T>
bool is_subnormal(const T x) noexcept
{
    return std::fpclassify(x) == FP_SUBNORMAL;
}

template <typename T>
double lexical_cast_to_double(const T& value)
{
    auto result = boost::lexical_cast<double>(value);
    if (is_subnormal(result)) {
        result = 0;
    }
    return result;
}

struct MeasureDoubleVisitor : boost::static_visitor<>
{
    double result;
    template <typename T> void operator()(const T& value)
    {
        result = lexical_cast_to_double(value);
    }
    template <typename T> void operator()(const boost::optional<T>& value)
    {
        if (value) {
            (*this)(*value);
        } else {
            result = -1;
        }
    }
    template <typename T> void operator()(const std::vector<T>& values)
    {
        throw std::runtime_error {"Vector cast not supported"};
    }
    void operator()(boost::any value)
    {
        throw std::runtime_error {"Any cast not supported"};
    }
};

auto cast_to_double(const Measure::ResultType& value)
{
    MeasureDoubleVisitor vis {};
    boost::apply_visitor(vis, value);
    return vis.result;
}

void skip_lines(std::istream& in, int n = 1)
{
    for (; n > 0; --n) in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

} // namespace

void RandomForestFilter::record(const std::size_t call_idx, std::size_t sample_idx, MeasureVector measures) const
{
    assert(!measures.empty());
    std::transform(std::cbegin(measures), std::cend(measures), std::back_inserter(data_buffer_[sample_idx]), cast_to_double);
    data_buffer_[sample_idx].push_back(0); // dummy TP value
    write_line(data_buffer_[sample_idx], data_[sample_idx].handle);
    data_buffer_[sample_idx].clear();
    if (call_idx >= num_records_) ++num_records_;
}

namespace {

bool read_header(std::ifstream& prediction_file)
{
    skip_lines(prediction_file);
    std::string order;
    std::getline(prediction_file, order);
    skip_lines(prediction_file);
    return order.front() == '1';
}

static double get_prob_false(std::string& prediction_line, const bool tp_first)
{
    using std::cbegin; using std::cend;
    if (tp_first) {
        prediction_line.erase(cbegin(prediction_line), std::next(std::find(cbegin(prediction_line), cend(prediction_line), ' ')));
        prediction_line.erase(std::find(cbegin(prediction_line), cend(prediction_line), ' '), cend(prediction_line));
    } else {
        prediction_line.erase(std::find(cbegin(prediction_line), cend(prediction_line), ' '), cend(prediction_line));
    }
    return boost::lexical_cast<double>(prediction_line);
}

} // namespace

void RandomForestFilter::prepare_for_classification(boost::optional<Log>& log) const
{
    const Path ranger_prefix {temp_dir_ / "octopus_ranger_temp"};
    const Path ranger_prediction_fname {ranger_prefix.string() + ".prediction"};
    data_buffer_.resize(num_records_);
    for (auto& file : data_) {
        file.handle.close();
        std::vector<std::string> tmp {}, cat_vars {};
        forest_->initCpp("TP", ranger::MemoryMode::MEM_DOUBLE, file.path.string(), 0, ranger_prefix.string(),
                         1000, nullptr, 12, 1, ranger_forest_.string(), ranger::ImportanceMode::IMP_GINI, 1, "",
                         tmp, "", true, cat_vars, false, ranger::SplitRule::LOGRANK, "", false, 1.0,
                         ranger::DEFAULT_ALPHA, ranger::DEFAULT_MINPROP, false,
                         ranger::PredictionType::RESPONSE, ranger::DEFAULT_NUM_RANDOM_SPLITS);
        forest_->run(false);
        forest_->writePredictionFile();
        std::ifstream prediction_file {ranger_prediction_fname.string()};
        const auto tp_first = read_header(prediction_file);
        std::string line;
        std::size_t record_idx {0};
        while (std::getline(prediction_file, line)) {
            if (!line.empty()) {
                data_buffer_[record_idx++].push_back(get_prob_false(line, tp_first));
            }
        }
        boost::filesystem::remove(file.path);
    }
    boost::filesystem::remove(ranger_prediction_fname);
    data_.clear();
    data_.shrink_to_fit();
}

VariantCallFilter::Classification RandomForestFilter::classify(const std::size_t call_idx, std::size_t sample_idx) const
{
    assert(call_idx < data_buffer_.size() && sample_idx < data_buffer_[call_idx].size());
    const auto prob_false = data_buffer_[call_idx][sample_idx];
    Classification result {};
    if (prob_false < 0.5) {
        result.category = Classification::Category::unfiltered;
    } else {
        result.category = Classification::Category::soft_filtered;
        result.reasons.assign({"RF"});
    }
    result.quality = probability_to_phred(std::max(prob_false, 1e-10));
    return result;
}

} // namespace csr
} // namespace octopus

ext: cpp

max_stars_repo_name: gmagoon/octopus

max_issues_repo_name: gmagoon/octopus

max_forks_repo_name: gmagoon/octopus


text:
// UscxmlCLibSrc.cpp : Defines the exported functions for the DLL application.

#include "../../include/UscxmlCLib.h"

#include <memory>
#include <bitset>

#include <boost/log/sinks/sync_frontend.hpp>

#include "uscxml/server/HTTPServer.h"

#include "UscxmlCLibBase.h"
#include "UscxmlClibLogger.h"

using namespace uscxml;

/* Global Library Variables */
std::string g_LAST_ERROR = "";
void SetLastUsclibError(const std::string &sErr) {
	g_LAST_ERROR = sErr;
	CLOG(ERROR) << __FUNCTION__ << "> " << g_LAST_ERROR;
}

bool g_HTTP_ENABLED = false;

std::set<UsclibInterpreter *> g_INTERPRETERS;

CALLBACK_USCLIB_GLOBAL_LOG g_GLOBAL_LOG_CALLBACK = nullptr;
void *g_GLOBAL_LOG_CALLBACK_USER = nullptr;

#define	CATCH_USCLIB_ALL		catch (uscxml::ErrorEvent &e) {	\
									std::stringstream ss;	\
									ss << e;	\
									SetLastUsclibError(ss.str()); }	\
								catch (std::exception &e) { SetLastUsclibError(e.what()); }	\
								catch (...) { SetLastUsclibError("Unknown exception"); }

#define CHECK_INTERPRETER_VALID(interpreter)	if (g_INTERPRETERS.find(interpreter)==g_INTERPRETERS.end()) \
												{ std::stringstream ss; ss << "UsclibInterpreter:[0x" <<  std::hex << \
												reinterpret_cast<int>(interpreter) << "] not initialized!"; throw std::exception(ss.str().c_str()); }

const char USCXMLCLIBAPI * usclib_GetLastError(void) {
	return g_LAST_ERROR.c_str();
}

int USCXMLCLIBAPI usclib_InitLogging(const char * chLogFileName, CALLBACK_USCLIB_GLOBAL_LOG ACallback, void *AUser)
{
	try
	{
		boost::log::register_simple_formatter_factory<SysLogSeverity, char>(boost::log::aux::default_attribute_names::severity());
		boost::log::register_simple_filter_factory<SysLogSeverity>(boost::log::aux::default_attribute_names::severity());

		boost::log::settings setts;

		if (chLogFileName) {
			setts["Sinks.File.Destination"] = "TextFile";
			setts["Sinks.File.FileName"] = chLogFileName;
			setts["Sinks.File.AutoFlush"] = true;
			setts["Sinks.File.Format"] = "[%TimeStamp%; %Severity%]: %Message%";
		}

		// Read the settings and initialize logging library
		boost::log::init_from_settings(setts);

		if (ACallback) {
			g_GLOBAL_LOG_CALLBACK = ACallback;
			g_GLOBAL_LOG_CALLBACK_USER = AUser;

			namespace sinks = boost::log::sinks;

			struct Sink : public sinks::basic_formatted_sink_backend<char, sinks::synchronized_feeding> {
				void consume(const boost::log::record_view& rec, const std::string& str) {
					if (g_GLOBAL_LOG_CALLBACK) {
						auto severity = rec.attribute_values()[boost::log::aux::default_attribute_names::severity()].extract<SysLogSeverity>();
						if (severity) {
							g_GLOBAL_LOG_CALLBACK(static_cast<int>(severity.get()), str.c_str(), g_GLOBAL_LOG_CALLBACK_USER);
						}
						else {
							g_GLOBAL_LOG_CALLBACK(static_cast<int>(SysLogSeverity::slDEBUG), str.c_str(), g_GLOBAL_LOG_CALLBACK_USER);
						}
					}
				}
			};

			typedef sinks::synchronous_sink<Sink> sink_t;
			boost::shared_ptr<sink_t> sink(new sink_t());
			boost::log::core::get()->add_sink(sink);
		}

		boost::log::add_common_attributes();

		return USCLIB_SUCCESS;
	} catch (std::exception& e) {
		g_LAST_ERROR = e.what();
	}
	catch (...) {
		g_LAST_ERROR = "Unknown exception";
	}
	return ERROR_USCLIB_INIT_LOG;
}

int USCXMLCLIBAPI usclib_OpenInterpreter(UsclibInterpreter **AInterpreter,
	const char **chCMD, const int nCMD, const UsclibInterpreterOptions *AInterpreterOptions) {
	try {
		std::vector<std::string> AVecString(chCMD, chCMD + nCMD);

		ScxmlBaseOptions AScxmlBaseOptions;

		if (AInterpreterOptions) {
			AScxmlBaseOptions.MonitorMsgTypes.clear();
			std::bitset<smttMAXSIZE+1> ABitMsgs(AInterpreterOptions->MonitorMsgTypes);
			for (std::size_t n = 0; n < ABitMsgs.size(); n++) {
				if (ABitMsgs[n]) {
					AScxmlBaseOptions.MonitorMsgTypes.insert(TScxmlMsgType(n));
				}
			}

			AScxmlBaseOptions.Monitor = AInterpreterOptions->Monitor;
			AScxmlBaseOptions.RemoteMonitorHost = AInterpreterOptions->RemoteMonitorHost;
			AScxmlBaseOptions.RemoteMonitorPort = AInterpreterOptions->RemoteMonitorPort;
			AScxmlBaseOptions.Validate = AInterpreterOptions->Validate;
			AScxmlBaseOptions.TerminateNotValidated = AInterpreterOptions->TerminateNotValidated;
			AScxmlBaseOptions.DisableGlobalData = AInterpreterOptions->DisableGlobalData;
			AScxmlBaseOptions.AsyncStart = AInterpreterOptions->AsyncStart;
		}

		/* 'USCXML cache option' may cause AccessViolation while reading cached JSON */
		setenv("USCXML_NOCACHE_FILES", "true", 1);

		ScxmlBase *AScxmlBase = new ScxmlBase(AVecString, AScxmlBaseOptions, g_HTTP_ENABLED);

		*AInterpreter = AScxmlBase;
		g_INTERPRETERS.insert(*AInterpreter);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_OPEN_INTERPRETER;
}

int USCXMLCLIBAPI usclib_CloseInterpreter(UsclibInterpreter *AInterpreter) {
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		g_INTERPRETERS.erase(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnStopped(nullptr, nullptr);
		delete AScxmlBase;

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_CLOSE_INTERPRETER;
}

int USCXMLCLIBAPI usclib_RegisterInterpreterLogCallback(UsclibInterpreter * AInterpreter, CALLBACK_USCLIB_INTERPRETER_LOG ACallback, void *AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnInterpreterLog(ACallback, AUser);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_REGISTER_CALLBACK;
}

int USCXMLCLIBAPI usclib_RegisterInterpreterEnterCallback(UsclibInterpreter * AInterpreter, CALLBACK_USCLIB_INTERPRETER_ENTER_EXIT ACallback, void * AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnEnter(ACallback, AUser);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_REGISTER_CALLBACK;
}

int USCXMLCLIBAPI usclib_RegisterInterpreterInvokeCallback(UsclibInterpreter * AInterpreter, CALLBACK_USCLIB_INTERPRETER_INVOKE ACallback,
	void * AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnInvoke(ACallback, AUser);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_REGISTER_CALLBACK;
}

int USCXMLCLIBAPI usclib_RegisterInterpreterEventCallback(UsclibInterpreter * AInterpreter, CALLBACK_USCLIB_INTERPRETER_EVENT ACallback,
	const UsclibDataType bAtomOrJson, void * AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnEvent(ACallback, bAtomOrJson, AUser);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_REGISTER_CALLBACK;
}

int USCXMLCLIBAPI usclib_RegisterInterpreterStoppedCallback(UsclibInterpreter * AInterpreter, CALLBACK_USCLIB_INTERPRETER_NOTIFY ACallback,
	void * AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnStopped(ACallback, AUser);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_REGISTER_CALLBACK;
}

int USCXMLCLIBAPI usclib_RegisterInterpreterGlobalDataChangeCallback(UsclibInterpreter * AInterpreter,
	CALLBACK_USCLIB_GLOBAL_DATA_CHANGE ACallback, const UsclibDataType bIsAtomOrJson, void * AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->registerOnGlobalDataChange(ACallback, bIsAtomOrJson, AUser);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_REGISTER_CALLBACK;
}

int USCXMLCLIBAPI usclib_StartInterpreter(UsclibInterpreter * AInterpreter, const char * chScxmlTextOrFile, const bool bIsText)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->start(chScxmlTextOrFile, bIsText);

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_START_INTERPRETER;
}

int USCXMLCLIBAPI usclib_PauseInterpreter(UsclibInterpreter * AInterpreter)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->pause();

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_PAUSE_INTERPRETER;
}

int USCXMLCLIBAPI usclib_ResumeInterpreter(UsclibInterpreter * AInterpreter)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->resume();

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_RESUME_INTERPRETER;
}

int USCXMLCLIBAPI usclib_StopInterpreter(UsclibInterpreter * AInterpreter)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->close();

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_STOP_INTERPRETER;
}

int USCXMLCLIBAPI usclib_WaitForInterpreterStopped(UsclibInterpreter * AInterpreter)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);
		AScxmlBase->waitForStopped();

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;
	return ERROR_USCLIB_WAIT_FOR_STOPPED;
}

int USCXMLCLIBAPI usclib_IsInterpreterInState(const UsclibInterpreter * AInterpreter, const char* chState, bool * bInState)
{
	try {
		CHECK_INTERPRETER_VALID(const_cast<UsclibInterpreter *>(AInterpreter));

		const ScxmlBase *AScxmlBase = reinterpret_cast<const ScxmlBase*>(AInterpreter);
		auto state = AScxmlBase->getState();
		if (state != USCXML_UNDEF && AScxmlBase->getImpl())
			*bInState = AScxmlBase->getImpl()->isInState(chState);
		else
			*bInState = false;

		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;
	return ERROR_USCLIB_IS_IN_STATE;
}

int USCXMLCLIBAPI usclib_InitHTTP(const int iHttpListenPort, const int iHttpWebsocketPort)
{
	try {
		HTTPServer::getInstance(iHttpListenPort, iHttpWebsocketPort);
		g_HTTP_ENABLED = true;
		return USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_INIT_HTTP;
}

int USCXMLCLIBAPI usclib_GetDefaultInterpreterOptions(UsclibInterpreterOptions * AInterpreterOptions)
{
	AInterpreterOptions->Monitor = true;
	AInterpreterOptions->RemoteMonitorHost = "127.0.0.1";
	AInterpreterOptions->RemoteMonitorPort = SCXML_DISABLE_REMOTE_MONITOR;
	AInterpreterOptions->Validate = true;
	AInterpreterOptions->TerminateNotValidated = true;
	AInterpreterOptions->MonitorMsgTypes = USCLIB_SCXMLEDITOR_MSG_TYPES;
	AInterpreterOptions->DisableGlobalData = false;

	return USCLIB_SUCCESS;
}

int USCXMLCLIBAPI usclib_Log(const unsigned int nSeverity, const char *chMessage) {

	BOOST_LOG_SEV(g_LOGGER::get(), SysLogSeverity(nSeverity)) << chMessage;

	return USCLIB_SUCCESS;
}

int USCXMLCLIBAPI usclib_TriggerEvent(UsclibInterpreter * AInterpreter, const char * chEvent)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		uscxml::Event AEvent;
		AEvent.eventType = uscxml::Event::EXTERNAL;
		AEvent.name = chEvent;

		AScxmlBase->receive(AEvent);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_TRIGGER_INT;
}

int USCXMLCLIBAPI usclib_TriggerIntEvent(UsclibInterpreter *AInterpreter, const char *chEvent, const int iData) {
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		uscxml::Event AEvent;
		AEvent.eventType = uscxml::Event::EXTERNAL;
		AEvent.name = chEvent;
		AEvent.data.atom = std::to_string(iData);
		AEvent.data.type = uscxml::Data::INTERPRETED;

		if (AScxmlBase->isGlobalDataEnabled())
			AScxmlBase->setGlobal(AEvent.name, "", AEvent.data, 0);

		AScxmlBase->receive(AEvent);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_TRIGGER_INT;
}

int USCXMLCLIBAPI usclib_TriggerDoubleEvent(UsclibInterpreter *AInterpreter, const char * chEvent, const double dData)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		uscxml::Event AEvent;
		AEvent.eventType = uscxml::Event::EXTERNAL;
		AEvent.name = chEvent;
		AEvent.data.atom = std::to_string(dData);
		AEvent.data.type = uscxml::Data::INTERPRETED;

		if (AScxmlBase->isGlobalDataEnabled())
			AScxmlBase->setGlobal(AEvent.name, "", AEvent.data, 0);
		AScxmlBase->receive(AEvent);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return  ERROR_USCLIB_TRIGGER_DBL;
}

int USCXMLCLIBAPI usclib_TriggerStringEvent(UsclibInterpreter *AInterpreter, const char * chEvent, const char * chData)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		uscxml::Event AEvent;
		AEvent.eventType = uscxml::Event::EXTERNAL;
		AEvent.name = chEvent;
		AEvent.data.atom = chData ? chData : "";
		AEvent.data.type = uscxml::Data::VERBATIM;

		if (AScxmlBase->isGlobalDataEnabled())
			AScxmlBase->setGlobal(AEvent.name, "", AEvent.data, 0);
		AScxmlBase->receive(AEvent);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return  ERROR_USCLIB_TRIGGER_STR;
}

int USCXMLCLIBAPI usclib_TriggerJsonEvent(UsclibInterpreter * AInterpreter, const char * chEvent, const char * chJsonData)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		uscxml::Event AEvent;
		AEvent.eventType = uscxml::Event::EXTERNAL;
		AEvent.name = chEvent;
		AEvent.data = uscxml::Data::fromJSON(chJsonData);

		if (AScxmlBase->isGlobalDataEnabled())
			AScxmlBase->setGlobal(AEvent.name, "", AEvent.data, 0);
		AScxmlBase->receive(AEvent);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_TRIGGER_JSON;
}

int USCXMLCLIBAPI usclib_GetGlobalData(UsclibInterpreter *AInterpreter,
	const char *chName, const char *chPath, CALLBACK_USCLIB_GET_GLOBAL_DATA ACallback, void *AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		if (!ACallback)
			throw std::exception("No need to return data for empty callback!");

		if (!chName)
			throw std::exception("'GetGlobalData' require non-empty name!");

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		auto data = AScxmlBase->getGlobal(chName, chPath ? chPath : "");
		ACallback(AInterpreter, chName, chPath, data.atom.c_str(), true/*atom data*/, AUser);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_DATA;
}

int USCXMLCLIBAPI usclib_GetGlobalJsonData(UsclibInterpreter * AInterpreter, const char * chName, const char * chPath, CALLBACK_USCLIB_GET_GLOBAL_DATA ACallback, void * AUser)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		if (!ACallback)
			throw std::exception("No need to return data for empty callback!");

		if (!chName)
			throw std::exception("'GetGlobalJsonData' require non-empty name!");

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		auto data = AScxmlBase->getGlobal(chName, chPath ? chPath : "");
		ACallback(AInterpreter, chName, chPath, data.asJSON().c_str(), false /*json data*/, AUser);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_DATA;
}

int USCXMLCLIBAPI usclib_SetGlobalIntData(UsclibInterpreter * AInterpreter, const char * chName, const char * chPath, const int iData, const int iType)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		if (!chName)
			throw std::exception("'usclib_SetGlobalStringData' require non-empty name!");

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		AScxmlBase->setGlobal(chName, chPath ? chPath : "", uscxml::Data(iData, uscxml::Data::INTERPRETED), iType);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_DATA;
}

int USCXMLCLIBAPI usclib_SetGlobalDoubleData(UsclibInterpreter * AInterpreter, const char * chName, const char * chPath, const double dData, const int iType)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		if (!chName)
			throw std::exception("'usclib_SetGlobalStringData' require non-empty name!");

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		AScxmlBase->setGlobal(chName, chPath ? chPath : "", uscxml::Data(dData, uscxml::Data::INTERPRETED), iType);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_DATA;
}

int USCXMLCLIBAPI usclib_SetGlobalStringData(UsclibInterpreter * AInterpreter, const char * chName, const char * chPath, const char * chData, const int iType)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		if (!chName)
			throw std::exception("'usclib_SetGlobalStringData' require non-empty name!");

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		AScxmlBase->setGlobal(chName, chPath ? chPath : "", chData ? uscxml::Data(chData, uscxml::Data::VERBATIM) : uscxml::Data(), iType);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_DATA;
}

int USCXMLCLIBAPI usclib_SetGlobalJsonData(UsclibInterpreter * AInterpreter,
	const char * chName, const char * chPath, const char * chJsonData, const int iType)
{
	try {
		CHECK_INTERPRETER_VALID(AInterpreter);

		if (!chName)
			throw std::exception("'usclib_SetGlobalJsonData' require non-empty name!");

		ScxmlBase *AScxmlBase = reinterpret_cast<ScxmlBase*>(AInterpreter);

		AScxmlBase->setGlobal(chName, chPath ? chPath : "", chJsonData ? uscxml::Data::fromJSON(chJsonData) : uscxml::Data(), iType);

		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_DATA;
}

int USCXMLCLIBAPI usclib_GlobalCleanup(void)
{
	try {
		Factory::getInstance().cleanup();
		return  USCLIB_SUCCESS;
	}
	CATCH_USCLIB_ALL;

	return ERROR_USCLIB_GLOBAL_CLEANUP;
}

max_stars_repo_name: alexzhornyak/UscxmlCLib

max_issues_repo_name: alexzhornyak/UscxmlCLib

max_forks_repo_name: alexzhornyak/UscxmlCLib


text:
// Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <config.h>

#include <asiolink/io_service.h>
#include <cc/command_interpreter.h>
#include <d2/d2_process.h>
#include <dhcp_ddns/ncr_io.h>
#include <process/testutils/d_test_stubs.h>
#include <d2/tests/nc_test_utils.h>

#include <boost/date_time/posix_time/posix_time.hpp>
#include <gtest/gtest.h>

#include <functional>
#include <sstream>

using namespace std;
using namespace isc;
using namespace isc::config;
using namespace isc::d2;
using namespace isc::process;
using namespace boost::posix_time;

namespace {

/// @brief Valid configuration containing an unavailable IP address.
const char* bad_ip_d2_config = "{ "
                        "\"ip-address\" : \"1.1.1.1\" , "
                        "\"port\" : 5031, "
                        "\"tsig-keys\": ["
                        "{ \"name\": \"d2_key.example.com\" , "
                        "   \"algorithm\": \"HMAC-MD5\" ,"
                        "   \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
                        "} ],"
                        "\"forward-ddns\" : {"
                        "\"ddns-domains\": [ "
                        "{ \"name\": \"example.com\" , "
                        "  \"key-name\": \"d2_key.example.com\" , "
                        "  \"dns-servers\" : [ "
                        "  { \"ip-address\": \"127.0.0.101\" } "
                        "] } ] }, "
                        "\"reverse-ddns\" : {"
                        "\"ddns-domains\": [ "
                        "{ \"name\": \" 0.168.192.in.addr.arpa.\" , "
                        "  \"key-name\": \"d2_key.example.com\" , "
                        "  \"dns-servers\" : [ "
                        "  { \"ip-address\": \"127.0.0.101\" , "
                        "    \"port\": 100 } ] } "
                        "] } }";

/// @brief D2Process test fixture class
//class D2ProcessTest : public D2Process, public ::testing::Test {
class D2ProcessTest : public D2Process, public ConfigParseTest {
public:

    /// @brief Constructor
    D2ProcessTest() :
        D2Process("d2test",
                  asiolink::IOServicePtr(new isc::asiolink::IOService())) {
    }

    /// @brief Destructor
    virtual ~D2ProcessTest() {
    }

    /// @brief Callback that will invoke shutdown method.
    void genShutdownCallback() {
        shutdown(isc::data::ConstElementPtr());
    }

    /// @brief Callback that throws an exception.
    void genFatalErrorCallback() {
        isc_throw (DProcessBaseError, "simulated fatal error");
    }

    /// @brief Reconfigures and starts the queue manager given a configuration.
    ///
    /// This method emulates the reception of a new configuration and should
    /// conclude with the Queue manager placed in the RUNNING state.
    ///
    /// @param config is the configuration to use
    ///
    /// @return Returns AssertionSuccess if the queue manager was successfully
    /// reconfigured, AssertionFailure otherwise.
    ::testing::AssertionResult runWithConfig(const char* config) {
        int rcode = -1;
        // Convert the string configuration into an Element set.
        ::testing::AssertionResult res = fromJSON(config);
        if (res != ::testing::AssertionSuccess()) {
            return res;
        }

        isc::data::ConstElementPtr answer = configure(config_set_, false);
        isc::data::ConstElementPtr comment;
        comment = isc::config::parseAnswer(rcode, answer);

        if (rcode) {
            return (::testing::AssertionFailure(::testing::Message() <<
                                                "configure() failed:"
                                                << comment));
        }

        // Must call checkQueueStatus, to cause queue manager to reconfigure
        // and start.
        checkQueueStatus();
        const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();

        // If queue manager isn't in the RUNNING state, return failure.
        if (D2QueueMgr::RUNNING !=  queue_mgr->getMgrState()) {
            return (::testing::AssertionFailure(::testing::Message() <<
                                               "queue manager did not start"));
        }

        //  Good to go.
        return (::testing::AssertionSuccess());
    }

    /// @brief Checks if shutdown criteria would be met given a shutdown type.
    ///
    /// This method sets the D2Process shutdown type to the given value, and
    /// calls the canShutdown() method, returning its return value.
    ///
    /// @return Returns the boolean result canShutdown.
    bool checkCanShutdown(ShutdownType shutdown_type) {
        setShutdownType(shutdown_type);
        return (canShutdown());
    }
};

/// @brief Verifies D2Process construction behavior.
/// 1. Verifies that constructor fails with an invalid IOService
/// 2. Verifies that constructor succeeds with a valid IOService
/// 3. Verifies that all managers are accessible
TEST(D2Process, construction) {
    // Verify that the constructor will fail if given an empty
    // io service.
    asiolink::IOServicePtr lcl_io_service;
    EXPECT_THROW (D2Process("TestProcess", lcl_io_service), DProcessBaseError);

    // Verify that the constructor succeeds with a valid io_service
    lcl_io_service.reset(new isc::asiolink::IOService());
    ASSERT_NO_THROW (D2Process("TestProcess", lcl_io_service));

    // Verify that the configuration, queue, and update managers
    // are all accessible after construction.
    D2Process d2process("TestProcess", lcl_io_service);

    D2CfgMgrPtr cfg_mgr = d2process.getD2CfgMgr();
    ASSERT_TRUE(cfg_mgr);

    D2QueueMgrPtr queue_mgr = d2process.getD2QueueMgr();
    ASSERT_TRUE(queue_mgr);

    const D2UpdateMgrPtr& update_mgr = d2process.getD2UpdateMgr();
    ASSERT_TRUE(update_mgr);
}

/// @brief Verifies basic configure method behavior.
/// This test primarily verifies that upon receipt of a new configuration,
/// D2Process will reconfigure the queue manager if the configuration is valid,
/// or leave queue manager unaffected if not.  Currently, the queue manager is
/// only D2 component that must adapt to new configurations. Other components,
/// such as Transactions will be unaffected as they are transient and use
/// whatever configuration was in play at the time they were created.
/// If other components need to provide "dynamic" configuration responses,
/// those tests would need to be added.
TEST_F(D2ProcessTest, configure) {
    // Verify the queue manager is not yet initialized.
    D2QueueMgrPtr queue_mgr = getD2QueueMgr();
    ASSERT_TRUE(queue_mgr);
    ASSERT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr->getMgrState());

    // Verify that reconfigure queue manager flag is false.
    ASSERT_FALSE(getReconfQueueFlag());

    // Create a valid configuration set from text config.
    ASSERT_TRUE(fromJSON(valid_d2_config));

    // Invoke configure() with a valid D2 configuration.
    isc::data::ConstElementPtr answer = configure(config_set_, false);

    // Verify that configure result is success and reconfigure queue manager
    // flag is true.
    ASSERT_TRUE(checkAnswer(answer, 0));
    ASSERT_TRUE(getReconfQueueFlag());

    // Call checkQueueStatus, to cause queue manager to reconfigure and start.
    checkQueueStatus();

    // Verify that queue manager is now in the RUNNING state, and flag is false.
    ASSERT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
    ASSERT_FALSE(getReconfQueueFlag());

    //  Create an invalid configuration set from text config.
    ASSERT_TRUE(fromJSON("{ \"bogus\": 1000 } "));

    // Invoke configure() with the invalid configuration.
    answer = configure(config_set_, false);

    // Verify that configure result is a success, as extra parameters are
    // ignored. the reconfigure flag is false, and that the queue manager is
    // still running.
    ASSERT_TRUE(checkAnswer(answer, 0));
    EXPECT_TRUE(getReconfQueueFlag());
    EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());

    // Finally, try with an invalid configuration.
    //  Create an invalid configuration set from text config.
    ASSERT_TRUE(fromJSON("{ \"ip-address\": \"950 Charter St.\" } "));
    answer = configure(config_set_, false);
    ASSERT_TRUE(checkAnswer(answer, 1));
    EXPECT_FALSE(getReconfQueueFlag());
    EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
}

/// @brief Tests checkQueueStatus() logic for stopping the queue on shutdown
/// This test manually sets shutdown flag and verifies that queue manager
/// stop is initiated.
TEST_F(D2ProcessTest, queueStopOnShutdown) {
    ASSERT_TRUE(runWithConfig(valid_d2_config));
    const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();

    setShutdownFlag(true);

    // Calling checkQueueStatus restart queue manager
    checkQueueStatus();

    // Verify that the queue manager is stopping.
    EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());

    // Verify that a subsequent call with no events occurring in between,
    // results in no change to queue manager
    checkQueueStatus();

    // Verify that the queue manager is still stopping.
    EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());

    // Call runIO so the IO cancel event occurs and verify that queue manager
    // has stopped.
    runIO();
    ASSERT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState());
}

/// @brief Tests checkQueueStatus() logic for stopping the queue on reconfigure.
/// This test manually sets queue reconfiguration flag and verifies that queue
/// manager stop is initiated.
TEST_F(D2ProcessTest, queueStopOnReconf) {
    ASSERT_TRUE(runWithConfig(valid_d2_config));
    const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();

    // Manually set the reconfigure indicator.
    setReconfQueueFlag(true);

    // Calling checkQueueStatus should initiate stopping the queue manager.
    checkQueueStatus();

    // Verify that the queue manager is stopping.
    EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());

    // Call runIO so the IO cancel event occurs and verify that queue manager
    // has stopped.
    runIO();
    ASSERT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState());
}

/// @brief Tests checkQueueStatus() logic for recovering from queue full
/// This test manually creates a receive queue full condition and then
/// "drains" the queue until the queue manager resumes listening.  This
/// verifies D2Process's ability to recover from a queue full condition.
TEST_F(D2ProcessTest, queueFullRecovery) {
    // Valid test message, contents are unimportant.
    const char* test_msg =
        "{"
        " \"change-type\" : 0 , "
        " \"forward-change\" : true , "
        " \"reverse-change\" : false , "
        " \"fqdn\" : \"walah.walah.com\" , "
        " \"ip-address\" : \"192.168.2.1\" , "
        " \"dhcid\" : \"010203040A7F8E3D\" , "
        " \"lease-expires-on\" : \"20130121132405\" , "
        " \"lease-length\" : 1300, "
        " \"use-conflict-resolution\" : true "
        "}";

    // Start queue manager with known good config.
    ASSERT_TRUE(runWithConfig(valid_d2_config));
    const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();

    // Set the maximum queue size to manageable number.
    size_t max_queue_size = 5;
    queue_mgr->setMaxQueueSize(max_queue_size);

    // Manually enqueue max requests.
    dhcp_ddns::NameChangeRequestPtr ncr;
    ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(test_msg));
    for (int i = 0; i < max_queue_size; i++) {
        // Verify that the request can be added to the queue and queue
        // size increments accordingly.
        ASSERT_NO_THROW(queue_mgr->enqueue(ncr));
        ASSERT_EQ(i+1, queue_mgr->getQueueSize());
    }

    // Since we are not really receiving, we will simulate QUEUE FULL
    // detection.
    queue_mgr->stopListening(D2QueueMgr::STOPPED_QUEUE_FULL);
    ASSERT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());

    // Call runIO so the IO cancel event occurs and verify that queue manager
    // has stopped.
    runIO();
    ASSERT_EQ(D2QueueMgr::STOPPED_QUEUE_FULL, queue_mgr->getMgrState());

    // Dequeue requests one at a time, calling checkQueueStatus after each
    // dequeue, until we reach the resume threshold.  This simulates update
    // manager consuming jobs.  Queue manager should remain stopped during
    // this loop.
    int resume_threshold = (max_queue_size * QUEUE_RESTART_PERCENT);
    while (queue_mgr->getQueueSize() > resume_threshold) {
        checkQueueStatus();
        ASSERT_EQ(D2QueueMgr::STOPPED_QUEUE_FULL, queue_mgr->getMgrState());
        ASSERT_NO_THROW(queue_mgr->dequeue());
    }

    // Dequeue one more, which brings us under the threshold and call
    // checkQueueStatus.
    // Verify that the queue manager is again running.
    ASSERT_NO_THROW(queue_mgr->dequeue());
    checkQueueStatus();
    EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
}

/// @brief Tests checkQueueStatus() logic for queue receive error recovery
/// This test manually creates a queue receive error condition and tests
/// verifies that checkQueueStatus reacts properly to recover.
TEST_F(D2ProcessTest, queueErrorRecovery) {
    ASSERT_TRUE(runWithConfig(valid_d2_config));
    const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();

    // Since we are not really receiving, we have to stage an error.
    queue_mgr->stopListening(D2QueueMgr::STOPPED_RECV_ERROR);
    ASSERT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());

    // Call runIO so the IO cancel event occurs and verify that queue manager
    // has stopped.
    runIO();
    ASSERT_EQ(D2QueueMgr::STOPPED_RECV_ERROR, queue_mgr->getMgrState());

    // Calling checkQueueStatus should restart queue manager
    checkQueueStatus();

    // Verify that queue manager is again running.
    EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
}

/// @brief Verifies queue manager recovery from unusable configuration
/// This test checks D2Process's gracefully handle a configuration which
/// while valid is not operationally usable (i.e. IP address is unavailable),
/// and to subsequently recover given a usable configuration.
TEST_F(D2ProcessTest, badConfigureRecovery) {
    D2QueueMgrPtr queue_mgr = getD2QueueMgr();
    ASSERT_TRUE(queue_mgr);

    // Verify the queue manager is not initialized.
    EXPECT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr->getMgrState());

    // Invoke configure() with a valid config that contains an unusable IP
    ASSERT_TRUE(fromJSON(bad_ip_d2_config));
    isc::data::ConstElementPtr answer = configure(config_set_, false);

    // Verify that configure result is success and reconfigure queue manager
    // flag is true.
    ASSERT_TRUE(checkAnswer(answer, 0));
    ASSERT_TRUE(getReconfQueueFlag());

    // Call checkQueueStatus to cause queue manager to attempt to reconfigure.
    checkQueueStatus();

    // Verify that queue manager  failed to start, (i.e. is in INITTED state),
    // and the the reconfigure flag is false.
    ASSERT_EQ(D2QueueMgr::INITTED, queue_mgr->getMgrState());
    ASSERT_FALSE(getReconfQueueFlag());

    // Verify we can recover given a valid config with an usable IP address.
    ASSERT_TRUE(fromJSON(valid_d2_config));
    answer = configure(config_set_, false);

    // Verify that configure result is success and reconfigure queue manager
    // flag is true.
    ASSERT_TRUE(checkAnswer(answer, 0));
    ASSERT_TRUE(getReconfQueueFlag());

    // Call checkQueueStatus to cause queue manager to reconfigure and start.
    checkQueueStatus();

    // Verify that queue manager is now in the RUNNING state, and reconfigure
    // flag is false.
    EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
    EXPECT_FALSE(getReconfQueueFlag());
}

/// @brief Tests shutdown command argument parsing
/// The shutdown command supports an optional "type" argument. This test
/// checks that for valid values, the shutdown() method: sets the shutdown
/// type to correct value, set the shutdown flag to true, and returns a
/// success response; and for invalid values: sets the shutdown flag to false
/// and returns a failure response.
TEST_F(D2ProcessTest, shutdownArgs) {
    isc::data::ElementPtr args;
    isc::data::ConstElementPtr answer;
    const char* default_args = "{}";
    const char* normal_args =  "{ \"type\" : \"normal\" }";
    const char* drain_args = "{ \"type\" : \"drain_first\" }";
    const char* now_args = "{ \"type\" : \"now\" }";
    const char* bogus_args = "{ \"type\" : \"bogus\" }";

    // Verify defaulting to SD_NORMAL if no argument is given.
    ASSERT_NO_THROW(args = isc::data::Element::fromJSON(default_args));
    EXPECT_NO_THROW(answer = shutdown(args));
    ASSERT_TRUE(checkAnswer(answer, 0));
    EXPECT_EQ(SD_NORMAL, getShutdownType());
    EXPECT_TRUE(shouldShutdown());

    // Verify argument value "normal".
    ASSERT_NO_THROW(args = isc::data::Element::fromJSON(normal_args));
    EXPECT_NO_THROW(answer = shutdown(args));
    ASSERT_TRUE(checkAnswer(answer, 0));
    EXPECT_EQ(SD_NORMAL, getShutdownType());
    EXPECT_TRUE(shouldShutdown());

    // Verify argument value "drain_first".
    ASSERT_NO_THROW(args = isc::data::Element::fromJSON(drain_args));
    EXPECT_NO_THROW(answer = shutdown(args));
    ASSERT_TRUE(checkAnswer(answer, 0));
    EXPECT_EQ(SD_DRAIN_FIRST, getShutdownType());
    EXPECT_TRUE(shouldShutdown());

    // Verify argument value "now".
    ASSERT_NO_THROW(args = isc::data::Element::fromJSON(now_args));
    EXPECT_NO_THROW(answer = shutdown(args));
    ASSERT_TRUE(checkAnswer(answer, 0));
    EXPECT_EQ(SD_NOW, getShutdownType());
    EXPECT_TRUE(shouldShutdown());

    // Verify correct handling of an invalid value.
    ASSERT_NO_THROW(args = isc::data::Element::fromJSON(bogus_args));
    EXPECT_NO_THROW(answer = shutdown(args));
    ASSERT_TRUE(checkAnswer(answer, 1));
    EXPECT_FALSE(shouldShutdown());
}

/// @brief Tests shutdown criteria logic
/// D2Process using the method canShutdown() to determine if a shutdown
/// can be performed given the value of the shutdown flag and the type of
/// shutdown requested.  For each shutdown type certain criteria must be met
/// before the shutdown is permitted.  This method is invoked once each pass
/// through the main event loop.  This test checks the operation of the
/// canShutdown method.  It uses a convenience method, checkCanShutdown(),
/// which sets the shutdown type to the given value and invokes canShutdown(),
/// returning its result.
TEST_F(D2ProcessTest, canShutdown) {
    ASSERT_TRUE(runWithConfig(valid_d2_config));
    const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();

    // Shutdown flag is false.  Method should return false for all types.
    EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
    EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
    EXPECT_FALSE(checkCanShutdown(SD_NOW));

    // Set shutdown flag to true.
    setShutdownFlag(true);

    // Queue Manager is running, queue is empty, no transactions.
    // Only SD_NOW should return true.
    EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
    EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
    EXPECT_TRUE(checkCanShutdown(SD_NOW));

    // Tell queue manager to stop.
    queue_mgr->stopListening();
    // Verify that the queue manager is stopping.
    EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());

    // Queue Manager is stopping, queue is empty, no transactions.
    // Only SD_NOW should return true.
    EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
    EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
    EXPECT_TRUE(checkCanShutdown(SD_NOW));

    // Allow cancel event to process.
    ASSERT_NO_THROW(runIO());
    // Verify that queue manager is stopped.
    EXPECT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState());

    // Queue Manager is stopped, queue is empty, no transactions.
    // All types should return true.
    EXPECT_TRUE(checkCanShutdown(SD_NORMAL));
    EXPECT_TRUE(checkCanShutdown(SD_DRAIN_FIRST));
    EXPECT_TRUE(checkCanShutdown(SD_NOW));

    const char* test_msg =
        "{"
        " \"change-type\" : 0 , "
        " \"forward-change\" : true , "
        " \"reverse-change\" : false , "
        " \"fqdn\" : \"fish.example.com\" , "
        " \"ip-address\" : \"192.168.2.1\" , "
        " \"dhcid\" : \"010203040A7F8E3D\" , "
        " \"lease-expires-on\" : \"20130121132405\" , "
        " \"lease-length\" : 1300, "
        " \"use-conflict-resolution\" : true "
        "}";

    // Manually enqueue a request.  This lets us test logic with queue
    // not empty.
    dhcp_ddns::NameChangeRequestPtr ncr;
    ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(test_msg));
    ASSERT_NO_THROW(queue_mgr->enqueue(ncr));
    ASSERT_EQ(1, queue_mgr->getQueueSize());

    // Queue Manager is stopped. Queue is not empty, no transactions.
    // SD_DRAIN_FIRST should be false, SD_NORMAL and SD_NOW should be true.
    EXPECT_TRUE(checkCanShutdown(SD_NORMAL));
    EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
    EXPECT_TRUE(checkCanShutdown(SD_NOW));

    // Now use update manager to dequeue the request and make a transaction.
    // This lets us verify transaction list not empty logic.
    const D2UpdateMgrPtr& update_mgr = getD2UpdateMgr();
    ASSERT_TRUE(update_mgr);
    ASSERT_NO_THROW(update_mgr->sweep());
    ASSERT_EQ(0, queue_mgr->getQueueSize());
    ASSERT_EQ(1, update_mgr->getTransactionCount());

    // Queue Manager is stopped. Queue is empty, one transaction.
    // Only SD_NOW should be true.
    EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
    EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
    EXPECT_TRUE(checkCanShutdown(SD_NOW));
}

/// @brief Verifies that an "external" call to shutdown causes the run method
/// to exit gracefully.
TEST_F(D2ProcessTest, normalShutdown) {
    // Use an asiolink IntervalTimer and callback to generate the
    // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
    isc::asiolink::IntervalTimer timer(*getIoService());
    timer.setup(std::bind(&D2ProcessTest::genShutdownCallback, this),
                2 * 1000);

    // Record start time, and invoke run().
    ptime start = microsec_clock::universal_time();
    EXPECT_NO_THROW(run());

    // Record stop time.
    ptime stop = microsec_clock::universal_time();

    // Verify that duration of the run invocation is the same as the
    // timer duration.  This demonstrates that the shutdown was driven
    // by an io_service event and callback.
    time_duration elapsed = stop - start;
    EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
                elapsed.total_milliseconds() <= 2200);
}

/// @brief Verifies that an "uncaught" exception thrown during event loop
/// execution is treated as a fatal error.
TEST_F(D2ProcessTest, fatalErrorShutdown) {
    // Use an asiolink IntervalTimer and callback to generate the
    // the exception.  (Note IntervalTimer setup is in milliseconds).
    isc::asiolink::IntervalTimer timer(*getIoService());
    timer.setup(std::bind(&D2ProcessTest::genFatalErrorCallback, this),
                2 * 1000);

    // Record start time, and invoke run().
    ptime start = microsec_clock::universal_time();
    EXPECT_THROW(run(), DProcessBaseError);

    // Record stop time.
    ptime stop = microsec_clock::universal_time();

    // Verify that duration of the run invocation is the same as the
    // timer duration.  This demonstrates that the anomaly occurred
    // during io callback processing.
    time_duration elapsed = stop - start;
    EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
                elapsed.total_milliseconds() <= 2200);
}

/// @brief Used to permit visual inspection of logs to ensure
/// DHCP_DDNS_NOT_ON_LOOPBACK is issued when ip_address is not
/// loopback.
TEST_F(D2ProcessTest, notLoopbackTest) {
    const char* config = "{ "
                        "\"ip-address\" : \"0.0.0.0\" , "
                        "\"port\" : 53001, "
                        "\"tsig-keys\": [],"
                        "\"forward-ddns\" : {},"
                        "\"reverse-ddns\" : {}"
                        "}";

    // Note we don't care nor can we predict if this
    // succeeds or fails. The address and port may or may
    // not be valid on the test host.
    runWithConfig(config);
}

/// @brief Used to permit visual inspection of logs to ensure
/// DHCP_DDNS_NOT_ON_LOOPBACK is not issued.
TEST_F(D2ProcessTest, v4LoopbackTest) {
    const char* config = "{ "
                        "\"ip-address\" : \"127.0.0.1\" , "
                        "\"port\" : 53001, "
                        "\"tsig-keys\": [],"
                        "\"forward-ddns\" : {},"
                        "\"reverse-ddns\" : {}"
                        "}";
    ASSERT_TRUE(runWithConfig(config));
}

/// @brief Used to permit visual inspection of logs to ensure
/// DHCP_DDNS_NOT_ON_LOOPBACK is not issued.
TEST_F(D2ProcessTest, v6LoopbackTest) {
    const char* config = "{ "
                        "\"ip-address\" : \"::1\" , "
                        "\"port\" : 53001, "
                        "\"tsig-keys\": [],"
                        "\"forward-ddns\" : {},"
                        "\"reverse-ddns\" : {}"
                        "}";
    ASSERT_TRUE(runWithConfig(config));
}

} // end of anonymous namespace

ext: cc


text:
// Copyright (C) 2013, Aldrin D'Souza.
// License: http://opensource.org/licenses/BSD-2-Clause

#include <misc/tree.hpp>
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>

typedef ajd::binary_tree<char> tree;
typedef boost::coroutines::coroutine<char()> generator;

bool is_leaf(tree::node l) { return !(l->left || l->right); }

void next_leaf(generator::caller_type& yield, tree::node& node)
{
  if(node) {
    next_leaf(yield, node->left);
    next_leaf(yield, node->right);
    if(is_leaf(node)) { yield(node->value); }
  }
}

bool same_fringe(tree::node one, tree::node two)
{
  generator leaf1(boost::bind(next_leaf, _1, one));
  generator leaf2(boost::bind(next_leaf, _1, two));
  for(; leaf1 && leaf2; leaf1(), leaf2()) {// iterate till *both* traversal are active
    if(leaf1.get() != leaf2().get()) {// compare the next leaf node
      return false;// return false, if they don't match.
    }
  }
  if(leaf1 || leaf2) {// if one of the traversals is still active,
    return false;// one tree has more leaves than the other.
  }
  return true;
}

int main()
{
  tree::node empty = tree::read_tree("");
  tree::node red = tree::read_tree("(-(-(-(X)(R))(-(I)(N)))(-(G)(E)))");
  tree::node blue1 = tree::read_tree("(-(-(-(F)(R))(-(I)(N)))(-(G)(E)))");
  tree::node blue2 = tree::read_tree("(-(-(-(-(-(F)(R))(I))(N))(G))(E))");
  tree::node blue3 = tree::read_tree("(-(-(-(-()(F))(R))(I))(-(-(-(N)())(G))(E))");
  tree::node diff = tree::read_tree("(-(-(-(-()(F))(R))(I))(-(-(-(N)())(G))())");
  assert(!same_fringe(empty, red));
  assert(!same_fringe(red, blue1));
  assert(same_fringe(empty, empty));
  assert(same_fringe(blue1, blue2));
  assert(same_fringe(blue2, blue3));
  assert(!same_fringe(blue2, diff));
}

max_stars_repo_name: aldrin/cpp

max_issues_repo_name: aldrin/cpp

max_forks_repo_name: aldrin/cpp


text:
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 Ferdinando Ametrano
 Copyright (C) 2006 Katiuscia Manzoni

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 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 license for more details.
*/

#ifndef quantlib_test_swaption_volatility_cube_hpp
#define quantlib_test_swaption_volatility_cube_hpp

#include <boost/test/unit_test.hpp>

/* remember to document new and/or updated tests in the Doxygen
   comment block of the corresponding class */

class SwaptionVolatilityCubeTest {
  public:
    static void testAtmVols();
    static void testSmile();
    static void testSabrVols();
    static void testSpreadedCube();
    static void testObservability();

    static boost::unit_test_framework::test_suite* suite();
};

#endif

ext: hpp


text: #include <boost/interprocess/containers/set.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#include "WebDirectory.h"
#include <Poco/Util/Application.h>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>

bool WebDirectory::load(const std::string& filename)
{
	Poco::Util::Application &app = Poco::Util::Application::instance();

	boost::property_tree::ptree tree;

	if (!boost::filesystem::exists(filename)) {
		app.logger().warning("configuration file \"" + filename + "\" not found");
		return false;
	}

	if (!boost::filesystem::is_regular(filename)) {
		app.logger().warning("configuration file \"" + filename + "\" is not regular file");
		return false;
	}

	// Parse the XML into the property tree.
	boost::property_tree::read_xml(filename, tree);

	m_path = tree.get<std::string>("directory.path");
	m_followSymLink = tree.get<bool>("directory.followSymLinks");
	m_showContent = tree.get<bool>("directory.indexes");

	/*boost::property_tree::ptree::const_assoc_iterator it = tree.find("directory.alias");
	if( it != tree.not_found() )
	{
		it->get_value<std::string>();
		//m_alias = tree.get<std::string>("directory.alias", "/");
	}*/

	boost::optional< boost::property_tree::ptree& > child = tree.get_child_optional( "directory.alias" );
	if(child) {
		m_alias = child->get_value<std::string>();
	}

	return true;
}

bool WebDirectory::validate() const
{
	if (!boost::filesystem::exists(m_path)) {
		Poco::Util::Application &app = Poco::Util::Application::instance();
		app.logger().warning("Document directory: \"" + m_path + "\" doesn't exists");
		return false;
	}

	if (!boost::filesystem::is_directory(m_path)) {
		Poco::Util::Application &app = Poco::Util::Application::instance();
		app.logger().warning("Document path: \"" + m_path + "\" is not directory");
		return false;
	}

	return true;
}

bool loadWebDirectories(const std::string& directory, WebDirectories& dirs)
{
	Poco::Util::Application &app = Poco::Util::Application::instance();

	if (!boost::filesystem::exists(directory)) {
		app.logger().warning("Web Hosts configuration directory \"" + directory + "\" not found");
		return false;
	}

	if (!boost::filesystem::is_directory(directory)) {
		app.logger().warning("Web Hosts configuration directory \"" + directory + "\" is not directory");
		return false;
	}

	boost::filesystem::directory_iterator it(directory), eod;

	BOOST_FOREACH(boost::filesystem::path const &p, std::make_pair(it, eod))
	{
		if(!boost::filesystem::is_regular_file(p)) {
			app.logger().warning("File \"" + p.string() +"\" is not regular file. Ignore it");
			continue;
		}

		if (boost::filesystem::extension(p) == "xml") {
			app.logger().warning("File \""+ p.string() +"\" is not xml file. Ignore it");
			continue;
		}

		WebDirectory directory;
		if (!directory.load(p.string())) {
			app.logger().warning("Can't load file \""+ p.relative_path().string() +"\". Ignore it");
			continue;
		}

		if (!directory.validate()) {
			app.logger().warning("Can't validate file \""+ p.relative_path().string() +"\". Ignore it");
			continue;
		}

		dirs.push_back(directory);

	} // end foreach

	return true;
}

max_stars_repo_name: feniksa/tinyhttpd

max_issues_repo_name: feniksa/tinyhttpd

max_forks_repo_name: feniksa/tinyhttpd


text:
#ifndef UDP_BROADCASTER_HPP
#define UDP_BROADCASTER_HPP

#include "experimental/network/utility.hpp"
#include <boost/asio/ip/udp.hpp>

namespace net {
namespace udp {

class broadcaster : public subscriber {
public:
  using udp = boost::asio::ip::udp;
  using error_code = boost::system::error_code;

  broadcaster(boost::asio::io_context &io_context,
              const udp::endpoint &broadcast_endpoint)
      : socket_(io_context) {
    socket_.connect(broadcast_endpoint);
    socket_.set_option(udp::socket::broadcast(true));
  }

private:
  void deliver(const std::string &msg) override {
    error_code ignored_error;
    socket_.send(boost::asio::buffer(msg), 0, ignored_error);
  }
  udp::socket socket_;
};

} // namespace udp
} // namespace net

#endif

max_stars_repo_name: mnrn/game-memo

max_issues_repo_name: mnrn/game-memo

max_forks_repo_name: mnrn/game-memo


text:
// Copyright 2019-present MongoDB Inc.
//
// 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.

#include <cast_core/actors/LoggingActor.hpp>

#include <boost/log/trivial.hpp>

#include <gennylib/Cast.hpp>
#include <gennylib/context.hpp>

namespace genny::actor {

//
// Note this Actor only has a manually-run test-case (LoggingActor_test.cpp).
// Be careful when making changes.
//

struct LoggingActor::PhaseConfig {
    TimeSpec logEvery;
    metrics::clock::time_point started;
    unsigned iteration = 0;

    explicit PhaseConfig(PhaseContext& phaseContext)
        : logEvery{phaseContext["LogEvery"].to<TimeSpec>()}, started{metrics::clock::now()} {
        if (phaseContext["Blocking"].to<std::string>() != "None") {
            BOOST_THROW_EXCEPTION(
                InvalidConfigurationException("LoggingActor must have Blocking:None"));
        }
    }
    void report() {
        // Avoid calling now() on most iterations
        if (++iteration % 10000 != 0) {
            return;
        }
        iteration = 0;

        const auto now = metrics::clock::now();
        const auto duration = now - started;
        if (duration >= logEvery.value) {
            BOOST_LOG_TRIVIAL(info) << "Phase still progressing.";
            started = now;
        }
    }
};

void LoggingActor::run() {
    for (auto&& config : _loop) {
        for (const auto&& _ : config) {
            config->report();
        }
    }
}

LoggingActor::LoggingActor(genny::ActorContext& context) : Actor{context}, _loop{context} {
    if (context["Threads"].to<size_t>() != 1) {
        BOOST_THROW_EXCEPTION(
            InvalidConfigurationException("LoggignActor must only have Threads:1"));
    }
}

namespace {
auto registerLoggingActor = Cast::registerDefault<LoggingActor>();
}  // namespace
}  // namespace genny::actor

max_stars_repo_name: samanca/genny

max_issues_repo_name: samanca/genny

max_forks_repo_name: samanca/genny


text:
#include <eosio/chain/webassembly/eos-vm-oc/executor.hpp>
#include <eosio/chain/webassembly/eos-vm-oc/code_cache.hpp>
#include <eosio/chain/webassembly/eos-vm-oc/memory.hpp>
#include <eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp>
#include <eosio/chain/webassembly/eos-vm-oc/intrinsic.hpp>
#include <eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.h>
#include <eosio/chain/wasm_eosio_constraints.hpp>
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/transaction_context.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/types.hpp>

#include <fc/scoped_exit.hpp>

#include <boost/hana/equal.hpp>

#include <asm/prctl.h>
#include <sys/prctl.h>
#include <sys/syscall.h>

#if defined(__has_feature)
#if __has_feature(shadow_call_stack)
#error PIZ VM OC is not compatible with Clang ShadowCallStack
#endif
#endif

extern "C" int arch_prctl(int code, unsigned long* addr);

namespace eosio { namespace chain { namespace eosvmoc {

static constexpr auto signal_sentinel = 0x4D56534F45534559ul;

static void(*chained_handler)(int,siginfo_t*,void*);
static void segv_handler(int sig, siginfo_t* info, void* ctx)  {
   control_block* cb_in_main_segment;

   //a 0 GS value is an indicator an executor hasn't been active on this thread recently
   uint64_t current_gs;
   syscall(SYS_arch_prctl, ARCH_GET_GS, &current_gs);
   if(current_gs == 0)
      goto notus;

   cb_in_main_segment = reinterpret_cast<control_block*>(current_gs - memory::cb_offset);

   //as a double check that the control block pointer is what we expect, look for the magic
   if(cb_in_main_segment->magic != signal_sentinel)
      goto notus;

   //was wasm running? If not, this SEGV was not due to us
   if(cb_in_main_segment->is_running == false)
      goto notus;

   //was the segfault within code?
   if((uintptr_t)info->si_addr >= cb_in_main_segment->execution_thread_code_start &&
      (uintptr_t)info->si_addr < cb_in_main_segment->execution_thread_code_start+cb_in_main_segment->execution_thread_code_length)
         siglongjmp(*cb_in_main_segment->jmp, PIZVMOC_EXIT_CHECKTIME_FAIL);

   //was the segfault within data?
   if((uintptr_t)info->si_addr >= cb_in_main_segment->execution_thread_memory_start &&
      (uintptr_t)info->si_addr < cb_in_main_segment->execution_thread_memory_start+cb_in_main_segment->execution_thread_memory_length)
         siglongjmp(*cb_in_main_segment->jmp, PIZVMOC_EXIT_SEGV);

notus:
   if(chained_handler) {
      chained_handler(sig, info, ctx);
      return;
   }
   ::signal(sig, SIG_DFL);
   ::raise(sig);
   __builtin_unreachable();
}

static intrinsic grow_memory_intrinsic PIZVMOC_INTRINSIC_INIT_PRIORITY("eosvmoc_internal.grow_memory", IR::FunctionType::get(IR::ResultType::i32,{IR::ValueType::i32,IR::ValueType::i32}),
  (void*)&eos_vm_oc_grow_memory,
  boost::hana::index_if(intrinsic_table, ::boost::hana::equal.to(BOOST_HANA_STRING("eosvmoc_internal.grow_memory"))).value()
);

//This is effectively overriding the eosio_exit intrinsic in wasm_interface
static void eosio_exit(int32_t code) {
   siglongjmp(*eos_vm_oc_get_jmp_buf(), PIZVMOC_EXIT_CLEAN_EXIT);
   __builtin_unreachable();
}
static intrinsic eosio_exit_intrinsic("env.eosio_exit", IR::FunctionType::get(IR::ResultType::none,{IR::ValueType::i32}), (void*)&eosio_exit,
  boost::hana::index_if(intrinsic_table, ::boost::hana::equal.to(BOOST_HANA_STRING("env.eosio_exit"))).value()
);

static void throw_internal_exception(const char* const s) {
   *reinterpret_cast<std::exception_ptr*>(eos_vm_oc_get_exception_ptr()) = std::make_exception_ptr(wasm_execution_error(FC_LOG_MESSAGE(error, s)));
   siglongjmp(*eos_vm_oc_get_jmp_buf(), PIZVMOC_EXIT_EXCEPTION);
   __builtin_unreachable();
}

#define DEFINE_PIZVMOC_TRAP_INTRINSIC(module,name) \
	void name(); \
	static intrinsic name##Function PIZVMOC_INTRINSIC_INIT_PRIORITY(#module "." #name,IR::FunctionType::get(),(void*)&name, \
     boost::hana::index_if(intrinsic_table, ::boost::hana::equal.to(BOOST_HANA_STRING(#module "." #name))).value() \
   ); \
	void name()

DEFINE_PIZVMOC_TRAP_INTRINSIC(eosvmoc_internal,depth_assert) {
   throw_internal_exception("Exceeded call depth maximum");
}

DEFINE_PIZVMOC_TRAP_INTRINSIC(eosvmoc_internal,div0_or_overflow) {
   throw_internal_exception("Division by 0 or integer overflow trapped");
}

DEFINE_PIZVMOC_TRAP_INTRINSIC(eosvmoc_internal,indirect_call_mismatch) {
   throw_internal_exception("Indirect call function type mismatch");
}

DEFINE_PIZVMOC_TRAP_INTRINSIC(eosvmoc_internal,indirect_call_oob) {
   throw_internal_exception("Indirect call index out of bounds");
}

DEFINE_PIZVMOC_TRAP_INTRINSIC(eosvmoc_internal,unreachable) {
   throw_internal_exception("Unreachable reached");
}

struct executor_signal_init {
   executor_signal_init() {
      struct sigaction sig_action, old_sig_action;
      sig_action.sa_sigaction = segv_handler;
      sigemptyset(&sig_action.sa_mask);
      sig_action.sa_flags = SA_SIGINFO | SA_NODEFER;
      sigaction(SIGSEGV, &sig_action, &old_sig_action);
      if(old_sig_action.sa_flags & SA_SIGINFO)
         chained_handler = old_sig_action.sa_sigaction;
      else if(old_sig_action.sa_handler != SIG_IGN && old_sig_action.sa_handler != SIG_DFL)
         chained_handler = (void (*)(int,siginfo_t*,void*))old_sig_action.sa_handler;
   }
};

executor::executor(const code_cache_base& cc) {
   //if we're the first executor created, go setup the signal handling. For now we'll just leave this attached forever
   static executor_signal_init the_executor_signal_init;

   uint64_t current_gs;
   if(arch_prctl(ARCH_GET_GS, &current_gs) || current_gs)
      wlog("x86_64 GS register is not set as expected. PIZ VM OC may not run correctly on this platform");

   struct stat s;
   FC_ASSERT(fstat(cc.fd(), &s) == 0, "executor failed to get code cache size");
   code_mapping = (uint8_t*)mmap(nullptr, s.st_size, PROT_EXEC|PROT_READ, MAP_SHARED, cc.fd(), 0);
   FC_ASSERT(code_mapping != MAP_FAILED, "failed to map code cache in to executor");
   code_mapping_size = s.st_size;
   mapping_is_executable = true;
}

void executor::execute(const code_descriptor& code, const memory& mem, apply_context& context) {
   if(mapping_is_executable == false) {
      mprotect(code_mapping, code_mapping_size, PROT_EXEC|PROT_READ);
      mapping_is_executable = true;
   }

   //prepare initial memory, mutable globals, and table data
   if(code.starting_memory_pages > 0 ) {
      arch_prctl(ARCH_SET_GS, (unsigned long*)(mem.zero_page_memory_base()+code.starting_memory_pages*memory::stride));
      memset(mem.full_page_memory_base(), 0, 64u*1024u*code.starting_memory_pages);
   }
   else
      arch_prctl(ARCH_SET_GS, (unsigned long*)mem.zero_page_memory_base());
   memcpy(mem.full_page_memory_base() - code.initdata_prologue_size, code_mapping + code.initdata_begin, code.initdata_size);

   control_block* const cb = mem.get_control_block();
   cb->magic = signal_sentinel;
   cb->execution_thread_code_start = (uintptr_t)code_mapping;
   cb->execution_thread_code_length = code_mapping_size;
   cb->execution_thread_memory_start = (uintptr_t)mem.start_of_memory_slices();
   cb->execution_thread_memory_length = mem.size_of_memory_slice_mapping();
   cb->ctx = &context;
   executors_exception_ptr = nullptr;
   cb->eptr = &executors_exception_ptr;
   cb->current_call_depth_remaining = eosio::chain::wasm_constraints::maximum_call_depth+2;
   cb->current_linear_memory_pages = code.starting_memory_pages;
   cb->first_invalid_memory_address = code.starting_memory_pages*64*1024;
   cb->full_linear_memory_start = (char*)mem.full_page_memory_base();
   cb->jmp = &executors_sigjmp_buf;
   cb->bounce_buffers = &executors_bounce_buffers;
   cb->running_code_base = (uintptr_t)(code_mapping + code.code_begin);
   cb->is_running = true;

   context.trx_context.transaction_timer.set_expiration_callback([](void* user) {
      executor* self = (executor*)user;
      syscall(SYS_mprotect, self->code_mapping, self->code_mapping_size, PROT_NONE);
      self->mapping_is_executable = false;
   }, this);
   context.trx_context.checktime(); //catch any expiration that might have occurred before setting up callback

   auto cleanup = fc::make_scoped_exit([cb, &tt=context.trx_context.transaction_timer](){
      cb->is_running = false;
      cb->bounce_buffers->clear();
      tt.set_expiration_callback(nullptr, nullptr);
   });

   void(*apply_func)(uint64_t, uint64_t, uint64_t) = (void(*)(uint64_t, uint64_t, uint64_t))(cb->running_code_base + code.apply_offset);

   switch(sigsetjmp(*cb->jmp, 0)) {
      case 0:
         code.start.visit(overloaded {
            [&](const no_offset&) {},
            [&](const intrinsic_ordinal& i) {
               void(*start_func)() = (void(*)())(*(uintptr_t*)((uintptr_t)mem.zero_page_memory_base() - memory::first_intrinsic_offset - i.ordinal*8));
               start_func();
            },
            [&](const code_offset& offs) {
               void(*start_func)() = (void(*)())(cb->running_code_base + offs.offset);
               start_func();
            }
         });
         apply_func(context.get_receiver().to_uint64_t(), context.get_action().account.to_uint64_t(), context.get_action().name.to_uint64_t());
         break;
      //case 1: clean eosio_exit
      case PIZVMOC_EXIT_CHECKTIME_FAIL:
         context.trx_context.checktime();
         break;
      case PIZVMOC_EXIT_SEGV:
         PIZ_ASSERT(false, wasm_execution_error, "access violation");
         break;
      case PIZVMOC_EXIT_EXCEPTION: //exception
         std::rethrow_exception(*cb->eptr);
         break;
   }
}

executor::~executor() {
   arch_prctl(ARCH_SET_GS, nullptr);
}

}}}

max_stars_repo_name: pizzachain/pizchain

max_issues_repo_name: pizzachain/pizchain

max_forks_repo_name: pizzachain/pizchain


text:
#include <fc/network/udp_socket.hpp>
#include <fc/network/ip.hpp>
#include <fc/network/resolve.hpp>
#include <fc/exception/exception.hpp>
#include <fc/log/gelf_appender.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/thread/thread.hpp>
#include <fc/variant.hpp>
#include <fc/io/json.hpp>
#include <fc/crypto/city.hpp>
#include <fc/compress/zlib.hpp>

#include <boost/lexical_cast.hpp>
#include <iomanip>
#include <iostream>
#include <queue>
#include <sstream>
#include <iostream>

namespace fc
{

  class gelf_appender::impl : public retainable
  {
  public:
    config                     cfg;
    optional<ip::endpoint>     gelf_endpoint;
    udp_socket                 gelf_socket;

    impl(const config& c) :
      cfg(c)
    {
    }

    ~impl()
    {
    }
  };

  gelf_appender::gelf_appender(const variant& args) :
    my( new impl( args.as<config>( FC_MAX_LOG_OBJECT_DEPTH ) ) )
  {
    try
    {
      try
      {
        // if it's a numeric address:port, this will parse it
        my->gelf_endpoint = ip::endpoint::from_string(my->cfg.endpoint);
      }
      catch (...)
      {
      }
      if (!my->gelf_endpoint)
      {
        // couldn't parse as a numeric ip address, try resolving as a DNS name.
        // This can yield, so don't do it in the catch block above
        string::size_type colon_pos = my->cfg.endpoint.find(':');
        try
        {
          uint16_t port = boost::lexical_cast<uint16_t>(my->cfg.endpoint.substr(colon_pos + 1, my->cfg.endpoint.size()));

          string hostname = my->cfg.endpoint.substr( 0, colon_pos );
          std::vector<ip::endpoint> endpoints = resolve(hostname, port);
          if (endpoints.empty())
              FC_THROW_EXCEPTION(unknown_host_exception, "The host name can not be resolved: ${hostname}",
                                 ("hostname", hostname));
          my->gelf_endpoint = endpoints.back();
        }
        catch (const boost::bad_lexical_cast&)
        {
          FC_THROW("Bad port: ${port}", ("port", my->cfg.endpoint.substr(colon_pos + 1, my->cfg.endpoint.size())));
        }
      }

      if (my->gelf_endpoint)
        my->gelf_socket.open();
    }
    catch (...)
    {
      std::cerr << "error opening GELF socket to endpoint ${endpoint}" << my->cfg.endpoint << "\n";
    }
  }

  gelf_appender::~gelf_appender()
  {}

  void gelf_appender::log(const log_message& message)
  {
    if (!my->gelf_endpoint)
      return;

    log_context context = message.get_context();

    mutable_variant_object gelf_message;
    gelf_message["version"] = "1.1";
    gelf_message["host"] = my->cfg.host;
    gelf_message["short_message"] = format_string( message.get_format(), message.get_data(), my->cfg.max_object_depth );

    gelf_message["timestamp"] = context.get_timestamp().time_since_epoch().count() / 1000000.;

    switch (context.get_log_level())
    {
    case log_level::debug:
      gelf_message["level"] = 7; // debug
      break;
    case log_level::info:
      gelf_message["level"] = 6; // info
      break;
    case log_level::warn:
      gelf_message["level"] = 4; // warning
      break;
    case log_level::error:
      gelf_message["level"] = 3; // error
      break;
    case log_level::all:
    case log_level::off:
      // these shouldn't be used in log messages, but do something deterministic just in case
      gelf_message["level"] = 6; // info
      break;
    }

    if (!context.get_context().empty())
      gelf_message["context"] = context.get_context();
    gelf_message["_line"] = context.get_line_number();
    gelf_message["_file"] = context.get_file();
    gelf_message["_method_name"] = context.get_method();
    if (!context.get_task_name().empty())
      gelf_message["_task_name"] = context.get_task_name();

    string gelf_message_as_string;
    try
    {
       gelf_message_as_string = json::to_string(gelf_message);
    }
    catch( const fc::assert_exception& e )
    {
       gelf_message_as_string = "{\"level\":3,\"short_message\":\"ERROR while generating log message\"}";
    }
    gelf_message_as_string = zlib_compress(gelf_message_as_string);

    // graylog2 expects the zlib header to be 0x78 0x9c
    // but miniz.c generates 0x78 0x01 (indicating
    // low compression instead of default compression)
    // so change that here
    assert(gelf_message_as_string[0] == (char)0x78);
    if (gelf_message_as_string[1] == (char)0x01 ||
        gelf_message_as_string[1] == (char)0xda)
      gelf_message_as_string[1] = (char)0x9c;
    assert(gelf_message_as_string[1] == (char)0x9c);

    // packets are sent by UDP, and they tend to disappear if they
    // get too large.  It's hard to find any solid numbers on how
    // large they can be before they get dropped -- datagrams can
    // be up to 64k, but anything over 512 is not guaranteed.
    // You can play with this number, intermediate values like
    // 1400 and 8100 are likely to work on most intranets.
    const unsigned max_payload_size = 512;

    if (gelf_message_as_string.size() <= max_payload_size)
    {
      // no need to split
      std::shared_ptr<char> send_buffer(new char[gelf_message_as_string.size()],
                                        [](char* p){ delete[] p; });
      memcpy(send_buffer.get(), gelf_message_as_string.c_str(),
             gelf_message_as_string.size());

      my->gelf_socket.send_to(send_buffer, gelf_message_as_string.size(),
                              *my->gelf_endpoint);
    }
    else
    {
      // split the message
      // we need to generate an 8-byte ID for this message.
      // city hash should do
      uint64_t message_id = city_hash64(gelf_message_as_string.c_str(), gelf_message_as_string.size());
      const unsigned header_length = 2 /* magic */ + 8 /* msg id */ + 1 /* seq */ + 1 /* count */;
      const unsigned body_length = max_payload_size - header_length;
      unsigned total_number_of_packets = (gelf_message_as_string.size() + body_length - 1) / body_length;
      unsigned bytes_sent = 0;
      unsigned number_of_packets_sent = 0;
      while (bytes_sent < gelf_message_as_string.size())
      {
        unsigned bytes_to_send = std::min((unsigned)gelf_message_as_string.size() - bytes_sent,
                                          body_length);

        std::shared_ptr<char> send_buffer(new char[max_payload_size],
                                          [](char* p){ delete[] p; });
        char* ptr = send_buffer.get();
        // magic number for chunked message
        *(unsigned char*)ptr++ = 0x1e;
        *(unsigned char*)ptr++ = 0x0f;

        // message id
        memcpy(ptr, (char*)&message_id, sizeof(message_id));
        ptr += sizeof(message_id);

        *(unsigned char*)(ptr++) = number_of_packets_sent;
        *(unsigned char*)(ptr++) = total_number_of_packets;
        memcpy(ptr, gelf_message_as_string.c_str() + bytes_sent,
               bytes_to_send);
        my->gelf_socket.send_to(send_buffer, header_length + bytes_to_send,
                                *my->gelf_endpoint);
        ++number_of_packets_sent;
        bytes_sent += bytes_to_send;
      }
      assert(number_of_packets_sent == total_number_of_packets);
    }
  }
} // fc

max_stars_repo_name: bitcoinmusicorg/bitcoinmusic-core

max_issues_repo_name: bitcoinmusicorg/bitcoinmusic-core

max_forks_repo_name: bitcoinmusicorg/bitcoinmusic-core


text:
/*=============================================================================
    Copyright (c) 2017 Paul Fultz II
    issue8.cpp
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/

#include "test.hpp"
#include <vector>
#include <boost/hof/pipable.hpp>
#include <boost/hof/placeholders.hpp>
#include <algorithm>

struct filter_fn
{
    template<class Input, class P>
    Input operator()(Input input, P pred) const
    {
        Input output(input.size());
        output.erase(
            ::std::copy_if(
                ::std::begin(input),
                ::std::end(input),
                ::std::begin(output),
                pred
            ),
            ::std::end(output)
        );
        return output;
    }
};

static constexpr boost::hof::pipable_adaptor<filter_fn> filter = {};

BOOST_HOF_TEST_CASE()
{
    std::vector<int> data;
    for(int i=0;i<6;i++)
    {
        data.push_back(i);
    }
    std::vector<int> r1 = data | filter(boost::hof::_1 > 1);
    BOOST_HOF_TEST_CHECK(r1.size() == 4);

    std::vector<int> r2 = filter(data, boost::hof::_1 > 1);
    BOOST_HOF_TEST_CHECK(r2.size() == 4);
}


text:
#include <utility>
#include <iostream>
#include <thread>
#include "ClientInterface.h"
#include "GameObjects.h"
#include <boost/asio.hpp>
#include "NetPart.h"
#include "GameEvents.h"

extern GameEssences gEssences;

constexpr int PortNumber = 56'000;

namespace {
	ClientInterface netInterface;
	tsdeq<OwnedMessage>& messages = netInterface.MessagesQueue();
	uint8_t pID = 0;
	int8_t sessionID = -1;
}

void SetText(sf::RenderWindow& window, std::string str);
Position GetInitialPosition(uint8_t id);

uint8_t ChooseSession(sf::RenderWindow& window, GameEssences& gEssences)
{
	if (!HasMessages())
		WaitMess();

	Message m = RecieveMessage();

	std::string sessionName;
	uint32_t sessionID;
	uint8_t gameMode;

	while (m.header.msize > 0)
	{
		m >> sessionID >> gameMode;
		sessionName = m.getString();
		std::cout << "Session name: " << sessionName << ", ID = "
			<< sessionID << ", max players: " << int(gameMode) << "\n";
	}

	WaitKeyPressed(window);
	/////////////////////////////////////////
	/*uint8_t ID;

	m >> ID;
	pID = ID;
	std::cout << "Received in-game id: " << int(ID) << std::endl;

	size_t messageSize = m.body.size();

	for (size_t i = 0; i < messageSize; ++i) {
		m >> ID;
		std::cout << "New player! ID: " << int(ID) << std::endl;
		gEssences.players[ID] = std::make_unique<Enemy>(GetInitialPosition(ID));
		gEssences.IDs[gEssences.players[ID]->GetPlayerType()] = ID;
	}

	return pID;*/
	return 0;
}

uint8_t ConnectToServer(sf::RenderWindow& window, GameEssences& gEssences)
{
	netInterface.Connect(boost::asio::ip::tcp::endpoint(
		boost::asio::ip::make_address("127.0.0.1"), PortNumber)
						);

	SetText(window, "Connecting...");

	while(!netInterface.IsConnected()) {} //Active waiting

	Message m;
	m.header.type = MessageType::GetSessions;

	SendMsg(m);

	//while(!HasMessages()) {} //Active waiting

	return ChooseSession(window, gEssences);
}

Message RecieveMessage()
{
	OwnedMessage m = messages.front();
	messages.pop_front();
	return m.message;
}

void SendMsg(Message m)
{
	m.header.owner = pID;
	m.header.sessionID = sessionID;
	netInterface.Send(m);
}

bool HasMessages()
{
	return !messages.empty();
}

void WaitMess()
{
	messages.waitMessage();
}


text:
/*
 * Copyright 2015-2019 CNRS-UM LIRMM, CNRS-AIST JRL
 */

#include <mc_rbdyn/CylindricalSurface.h>
#include <mc_rbdyn/GripperSurface.h>
#include <mc_rbdyn/PlanarSurface.h>
#include <mc_rbdyn/rpy_utils.h>
#include <mc_rbdyn/surface_utils.h>

// For some dom manipulations
#include <mc_rbdyn_urdf/urdf.h>

#include <boost/filesystem.hpp>

#include <fstream>
#include <tinyxml2.h>

namespace bfs = boost::filesystem;

namespace mc_rbdyn
{

inline sva::PTransformd tfFromOriginDom(const tinyxml2::XMLElement & dom)
{
  Eigen::Vector3d xyz = mc_rbdyn_urdf::attrToVector(dom, "xyz");
  Eigen::Vector3d rpy = mc_rbdyn_urdf::attrToVector(dom, "rpy");
  return sva::PTransformd(rpyToMat(rpy), xyz);
}

inline void readRSDF(const std::string & rsdf_string, std::vector<std::shared_ptr<Surface>> & surfaces)
{
  tinyxml2::XMLDocument doc;
  doc.Parse(rsdf_string.c_str());

  tinyxml2::XMLElement * root = doc.FirstChildElement("robot");
  std::vector<tinyxml2::XMLElement *> psurfaces;
  {
    tinyxml2::XMLElement * psurface = root->FirstChildElement("planar_surface");
    while(psurface)
    {
      psurfaces.push_back(psurface);
      psurface = psurface->NextSiblingElement("planar_surface");
    }
  }
  for(tinyxml2::XMLElement * pdom : psurfaces)
  {
    std::string name = pdom->Attribute("name");
    std::string bodyName = pdom->Attribute("link");
    sva::PTransformd X_b_s = tfFromOriginDom(*(pdom->FirstChildElement("origin")));
    std::string materialName = pdom->FirstChildElement("material")->Attribute("name");
    std::vector<std::pair<double, double>> points;
    tinyxml2::XMLElement * pointdom = pdom->FirstChildElement("points")->FirstChildElement("point");
    while(pointdom)
    {
      std::vector<double> pdata = mc_rbdyn_urdf::attrToList(*pointdom, "xy");
      points.push_back(std::pair<double, double>(pdata[0], pdata[1]));
      pointdom = pointdom->NextSiblingElement("point");
    }
    surfaces.push_back(std::shared_ptr<Surface>(new PlanarSurface(name, bodyName, X_b_s, materialName, points)));
  }

  std::vector<tinyxml2::XMLElement *> csurfaces;
  {
    tinyxml2::XMLElement * csurface = root->FirstChildElement("cylindrical_surface");
    while(csurface)
    {
      csurfaces.push_back(csurface);
      csurface = csurface->NextSiblingElement("cylindrical_surface");
    }
  }
  for(tinyxml2::XMLElement * cdom : csurfaces)
  {
    std::string name = cdom->Attribute("name");
    std::string bodyName = cdom->Attribute("link");
    double width = cdom->DoubleAttribute("width");
    double radius = cdom->DoubleAttribute("radius");
    sva::PTransformd X_b_s = tfFromOriginDom(*(cdom->FirstChildElement("origin")));
    std::string materialName = cdom->FirstChildElement("material")->Attribute("name");
    surfaces.push_back(
        std::shared_ptr<Surface>(new CylindricalSurface(name, bodyName, X_b_s, materialName, radius, width)));
  }

  std::vector<tinyxml2::XMLElement *> gsurfaces;
  {
    tinyxml2::XMLElement * gsurface = root->FirstChildElement("gripper_surface");
    while(gsurface)
    {
      gsurfaces.push_back(gsurface);
      gsurface = gsurface->NextSiblingElement("gripper_surface");
    }
  }
  for(tinyxml2::XMLElement * gdom : gsurfaces)
  {
    std::string name = gdom->Attribute("name");
    std::string bodyName = gdom->Attribute("link");
    sva::PTransformd X_b_s = tfFromOriginDom(*(gdom->FirstChildElement("origin")));
    std::string materialName = gdom->FirstChildElement("material")->Attribute("name");
    tinyxml2::XMLElement * motorDom = gdom->FirstChildElement("motor");
    sva::PTransformd X_b_motor = tfFromOriginDom(*motorDom);
    double motorMaxTorque = motorDom->DoubleAttribute("max_torque");
    std::vector<sva::PTransformd> points;
    tinyxml2::XMLElement * pointdom = gdom->FirstChildElement("points")->FirstChildElement("origin");
    while(pointdom)
    {
      points.push_back(tfFromOriginDom(*pointdom));
      pointdom = pointdom->NextSiblingElement("origin");
    }
    surfaces.push_back(std::shared_ptr<Surface>(
        new GripperSurface(name, bodyName, X_b_s, materialName, points, X_b_motor, motorMaxTorque)));
  }
}

std::vector<std::shared_ptr<Surface>> readRSDFFromDir(const std::string & dirname)
{
  std::vector<std::shared_ptr<Surface>> res;

  bfs::path p(dirname);

  if(bfs::exists(p) && bfs::is_directory(p))
  {
    std::vector<bfs::path> files;
    std::copy(bfs::directory_iterator(p), bfs::directory_iterator(), std::back_inserter(files));
    for(const bfs::path & file : files)
    {
      if(file.extension() == ".rsdf")
      {
        std::ifstream ifs(file.string());
        std::stringstream ss;
        ss << ifs.rdbuf();
        readRSDF(ss.str(), res);
      }
    }
  }

  return res;
}

} // namespace mc_rbdyn