<commit_before>#include "curltools.h"

#include "json_spirit.h"
#include "util.h"
#include <boost/thread.hpp>
#include <iostream>
#include <openssl/ssl.h>

boost::once_flag init_openssl_once_flag     = BOOST_ONCE_INIT;
boost::once_flag init_curl_global_once_flag = BOOST_ONCE_INIT;
boost::mutex     curl_global_init_lock;

class CurlCleaner
{
    CURL* curl_obj_to_clean;

public:
    CurlCleaner(CURL* Curl_obj_to_clean) : curl_obj_to_clean(Curl_obj_to_clean) {}

    ~CurlCleaner() { curl_easy_cleanup(curl_obj_to_clean); }
};

size_t cURLTools::CurlWrite_CallbackFunc_StdString(void* contents, size_t size, size_t nmemb,
                                                   std::deque<char>* s)
{
    size_t newLength = size * nmemb;
    size_t oldLength = s->size();
    try {
        s->resize(oldLength + newLength);
    } catch (std::bad_alloc& e) {
        std::stringstream msg;
        msg << "Error allocating memory: " << e.what() << std::endl;
        printf("%s", msg.str().c_str());
        return 0;
    }

    std::copy((char*)contents, (char*)contents + newLength, s->begin() + oldLength);
    return size * nmemb;
}

size_t cURLTools::CurlRead_CallbackFunc_StdString(void* dest, size_t /*size*/, size_t /*nmemb*/,
                                                  void* userp)
{
    std::string* from = (std::string*)userp;
    std::string* to   = (std::string*)dest;

    std::copy(from->begin(), from->end(), std::back_inserter(*to));

    return 0; /* no more data left to deliver */
}

size_t cURLTools::CurlWrite_CallbackFunc_File(void* contents, size_t size, size_t nmemb,
                                              boost::filesystem::fstream* fs)
{
    size_t newLength = size * nmemb;
    fs->write(reinterpret_cast<char*>(contents), newLength);
    return size * nmemb;
}

int cURLTools::CurlProgress_CallbackFunc(void*, double TotalToDownload, double NowDownloaded,
                                         double /*TotalToUpload*/, double /*NowUploaded*/)
{
    std::clog << "Download progress: " << ToString(NowDownloaded) << " / " << ToString(TotalToDownload)
              << std::endl;
    return CURLE_OK;
}

int cURLTools::CurlAtomicProgress_CallbackFunc(void* number, double TotalToDownload,
                                               double NowDownloaded, double /*TotalToUpload*/,
                                               double /*NowUploaded*/)
{
    std::atomic<float>* progress = reinterpret_cast<std::atomic<float>*>(number);
    float               val      = 0;
    if (NowDownloaded > 0.) {
        val = static_cast<float>( NowDownloaded / 1000 / 1000); // bytes to MB
        if (val < 0.0001) {
            val = 0;
        }
    }
    progress->store(val, std::memory_order_relaxed);
    return CURLE_OK;
}

void cURLTools::CurlGlobalInit_ThreadSafe()
{
    boost::lock_guard<boost::mutex> lg(curl_global_init_lock);
    curl_global_init(CURL_GLOBAL_DEFAULT);
}

void cURLTools::GetLargeFileFromHTTPS(const std::string& URL, long ConnectionTimeout,
                                      const boost::filesystem::path& targetPath,
                                      std::atomic<float>&            progress,
                                      const std::set<CURLcode>&      errorsToIgnore)
{

#if OPENSSL_VERSION_NUMBER < 0x10100000L
    boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
    boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0,
                     static_cast<const ossl_init_settings_st*>(NULL));
#endif

    CURL*    curl;
    CURLcode res;

    boost::call_once(init_curl_global_once_flag, CurlGlobalInit_ThreadSafe);

    curl = curl_easy_init();
    boost::filesystem::fstream outputStream(targetPath, std::ios::out | std::ios::binary);

    std::string agent = GetUserAgent();
    if (curl) {

        CurlCleaner cleaner(curl);

        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_File);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outputStream);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, agent.c_str());

        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, CurlAtomicProgress_CallbackFunc);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progress);
        // curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //verbose output
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);

        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK && errorsToIgnore.find(res) == errorsToIgnore.cend()) {
            std::string errorMsg(curl_easy_strerror(res));
            printf("Curl error: %s\n", errorMsg.c_str());
            throw std::runtime_error(std::string(errorMsg).c_str());
        } else {
            long http_response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
            if (http_response_code != 200) {
                std::string errorMsg("Error retrieving data with https protocol from URL \"" + URL +
                                     "\", error code: " + ToString(http_response_code) +
                                     ". Probably the URL is invalid.");
                printf("Curl http code error: %s\n", errorMsg.c_str());
                throw std::runtime_error(errorMsg);
            }
        }

        /* always cleanup */
        // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
        // curl_easy_cleanup(curl);
    }
}

std::string cURLTools::GetUserAgent()
{
    std::string agent;
#ifdef QT_GUI
    agent += "Neblio-Qt";
#else
    agent += "Neblio";
#endif
    std::string version =
        std::to_string(CLIENT_VERSION_MAJOR) + "." + std::to_string(CLIENT_VERSION_MINOR) + "." +
        std::to_string(CLIENT_VERSION_REVISION) + "." + std::to_string(CLIENT_VERSION_BUILD);
    agent += "/";
    agent += version;
    return agent;
}

std::string cURLTools::GetFileFromHTTPS(const std::string& URL, long ConnectionTimeout,
                                        bool IncludeProgressBar)
{

#if OPENSSL_VERSION_NUMBER < 0x10100000L
    boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
    boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0,
                     static_cast<const ossl_init_settings_st*>(NULL));
#endif

    CURL*    curl;
    CURLcode res;

    boost::call_once(init_curl_global_once_flag, CurlGlobalInit_ThreadSafe);

    curl = curl_easy_init();
    std::deque<char> s;

    std::string agent = GetUserAgent();
    if (curl) {

        CurlCleaner cleaner(curl);

        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, agent.c_str());
        if (IncludeProgressBar) {
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
            curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, CurlProgress_CallbackFunc);
        } else {
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
        }
        // curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //verbose output
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK) {
            std::string errorMsg(curl_easy_strerror(res));
            throw std::runtime_error(std::string(errorMsg).c_str());
        } else {
            long http_response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
            if (http_response_code != 200) {
                throw std::runtime_error("Error retrieving data with https protocol from URL \"" + URL +
                                         "\", error code: " + ToString(http_response_code) +
                                         ". Probably the URL is invalid.");
            }
        }

        /* always cleanup */
        // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
        // curl_easy_cleanup(curl);
    }
    std::string fileStr(s.begin(), s.end());
    return fileStr;
}

std::string cURLTools::PostJsonToHTTPS(const std::string& URL, long ConnectionTimeout,
                                       const std::string& readdata, bool chunked)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
    boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
    boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0,
                     static_cast<const ossl_init_settings_st*>(NULL));
#endif

    CURL*    curl;
    CURLcode res;

    boost::call_once(init_curl_global_once_flag, CurlGlobalInit_ThreadSafe);

    /* get a curl handle */
    curl = curl_easy_init();
    std::deque<char> writedata;
    std::string      agent = GetUserAgent();
    if (curl) {

        CurlCleaner cleaner(curl);

        struct curl_slist* headers = NULL;

        /* First set the URL that is about to receive our POST. This URL can
         just as well be a https:// URL if that is what should receive the
         data. */
        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        //        curl_easy_setopt(curl, CURLOPT_READDATA, &readdata);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writedata);
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, CurlRead_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
        /* Now specify the POST data */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, readdata.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, agent.c_str());

        headers = curl_slist_append(headers, "Content-Type: application/json");
        headers = curl_slist_append(headers, "charsets: utf-8");

        // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // verbose output
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);
        if (chunked) {

            headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
            /* use curl_slist_free_all() after the *perform() call to free this
         list again */
        } else {
            /* Set the expected POST size. If you want to POST large amounts of data,
       consider CURLOPT_POSTFIELDSIZE_LARGE */
            curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)readdata.size());
        }

        /*
              Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue"
              header.  You can disable this header with CURLOPT_HTTPHEADER as usual.
              NOTE: if you want chunked transfer too, you need to combine these two
              since you can only set one list of headers with CURLOPT_HTTPHEADER. */

        /* A less good option would be to enforce HTTP 1.0, but that might also
               have other implications. */
        const bool disable_expect = false;
        if (disable_expect) {
            headers = curl_slist_append(headers, "Expect:");
            /* use curl_slist_free_all() after the *perform() call to free this
                 list again */
        }

        res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK) {
            std::string errorMsg(curl_easy_strerror(res));
            throw std::runtime_error(std::string(errorMsg).c_str());
        } else {
            long http_response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
            if (http_response_code != 200) {
                json_spirit::Value errorData;
                if (json_spirit::read(std::string(writedata.begin(), writedata.end()), errorData)) {
                    json_spirit::Value errorMsg;
                    errorMsg = json_spirit::find_value(errorData.get_obj(), "message");
                    throw std::runtime_error("Failed to create transaction with error: " +
                                             errorMsg.get_str());
                } else {
                    throw std::runtime_error("Error posting data with https protocol from URL \"" + URL +
                                             "\", error code: " + ToString(http_response_code) +
                                             ". Probably the URL is invalid. Could not retrieve more "
                                             "information on the error.");
                }
            }
        }

        /* always cleanup */
        // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
        // curl_easy_cleanup(curl);
    }
    std::string fileStr(writedata.begin(), writedata.end());
    return fileStr;
}
<commit_msg>Update curltools.cpp<commit_after>#include "curltools.h"

#include "json_spirit.h"
#include "util.h"
#include <boost/thread.hpp>
#include <iostream>
#include <openssl/ssl.h>

boost::once_flag init_openssl_once_flag     = BOOST_ONCE_INIT;
boost::once_flag init_curl_global_once_flag = BOOST_ONCE_INIT;
boost::mutex     curl_global_init_lock;

class CurlCleaner
{
    CURL* curl_obj_to_clean;

public:
    CurlCleaner(CURL* Curl_obj_to_clean) : curl_obj_to_clean(Curl_obj_to_clean) {}

    ~CurlCleaner() { curl_easy_cleanup(curl_obj_to_clean); }
};

size_t cURLTools::CurlWrite_CallbackFunc_StdString(void* contents, size_t size, size_t nmemb,
                                                   std::deque<char>* s)
{
    size_t newLength = size * nmemb;
    size_t oldLength = s->size();
    try {
        s->resize(oldLength + newLength);
    } catch (std::bad_alloc& e) {
        std::stringstream msg;
        msg << "Error allocating memory: " << e.what() << std::endl;
        printf("%s", msg.str().c_str());
        return 0;
    }

    std::copy((char*)contents, (char*)contents + newLength, s->begin() + oldLength);
    return size * nmemb;
}

size_t cURLTools::CurlRead_CallbackFunc_StdString(void* dest, size_t /*size*/, size_t /*nmemb*/,
                                                  void* userp)
{
    std::string* from = (std::string*)userp;
    std::string* to   = (std::string*)dest;

    std::copy(from->begin(), from->end(), std::back_inserter(*to));

    return 0; /* no more data left to deliver */
}

size_t cURLTools::CurlWrite_CallbackFunc_File(void* contents, size_t size, size_t nmemb,
                                              boost::filesystem::fstream* fs)
{
    size_t newLength = size * nmemb;
    fs->write(reinterpret_cast<char*>(contents), newLength);
    return size * nmemb;
}

int cURLTools::CurlProgress_CallbackFunc(void*, double TotalToDownload, double NowDownloaded,
                                         double /*TotalToUpload*/, double /*NowUploaded*/)
{
    std::clog << "Download progress: " << ToString(NowDownloaded) << " / " << ToString(TotalToDownload)
              << std::endl;
    return CURLE_OK;
}

int cURLTools::CurlAtomicProgress_CallbackFunc(void* number, double TotalToDownload,
                                               double NowDownloaded, double /*TotalToUpload*/,
                                               double /*NowUploaded*/)
{
    std::atomic<float>* progress = reinterpret_cast<std::atomic<float>*>(number);
    float               val      = 0;
    if (NowDownloaded > 0.) {
        val = static_cast<float>( NowDownloaded / 1000 / 1000); // bytes to MB
        if (val < 0.0001) {
            val = 0;
        }
    }
    progress->store(val, std::memory_order_relaxed);
    return CURLE_OK;
}

void cURLTools::CurlGlobalInit_ThreadSafe()
{
    boost::lock_guard<boost::mutex> lg(curl_global_init_lock);
    curl_global_init(CURL_GLOBAL_DEFAULT);
}

void cURLTools::GetLargeFileFromHTTPS(const std::string& URL, long ConnectionTimeout,
                                      const boost::filesystem::path& targetPath,
                                      std::atomic<float>&            progress,
                                      const std::set<CURLcode>&      errorsToIgnore)
{

#if OPENSSL_VERSION_NUMBER < 0x10100000L
    boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
    boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0,
                     static_cast<const ossl_init_settings_st*>(NULL));
#endif

    CURL*    curl;
    CURLcode res;

    boost::call_once(init_curl_global_once_flag, CurlGlobalInit_ThreadSafe);

    curl = curl_easy_init();
    boost::filesystem::fstream outputStream(targetPath, std::ios::out | std::ios::binary);

    std::string agent = GetUserAgent();
    if (curl) {

        CurlCleaner cleaner(curl);

        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_File);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outputStream);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, agent.c_str());

        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, CurlAtomicProgress_CallbackFunc);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progress);
        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //verbose output
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);

        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK && errorsToIgnore.find(res) == errorsToIgnore.cend()) {
            std::string errorMsg(curl_easy_strerror(res));
            printf("Curl error: %s\n", errorMsg.c_str());
            throw std::runtime_error(std::string(errorMsg).c_str());
        } else {
            long http_response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
            if (http_response_code != 200) {
                std::string errorMsg("Error retrieving data with https protocol from URL \"" + URL +
                                     "\", error code: " + ToString(http_response_code) +
                                     ". Probably the URL is invalid.");
                printf("Curl http code error: %s\n", errorMsg.c_str());
                throw std::runtime_error(errorMsg);
            }
        }

        /* always cleanup */
        // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
        // curl_easy_cleanup(curl);
    }
}

std::string cURLTools::GetUserAgent()
{
    std::string agent;
#ifdef QT_GUI
    agent += "Neblio-Qt";
#else
    agent += "Neblio";
#endif
    std::string version =
        std::to_string(CLIENT_VERSION_MAJOR) + "." + std::to_string(CLIENT_VERSION_MINOR) + "." +
        std::to_string(CLIENT_VERSION_REVISION) + "." + std::to_string(CLIENT_VERSION_BUILD);
    agent += "/";
    agent += version;
    return agent;
}

std::string cURLTools::GetFileFromHTTPS(const std::string& URL, long ConnectionTimeout,
                                        bool IncludeProgressBar)
{

#if OPENSSL_VERSION_NUMBER < 0x10100000L
    boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
    boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0,
                     static_cast<const ossl_init_settings_st*>(NULL));
#endif

    CURL*    curl;
    CURLcode res;

    boost::call_once(init_curl_global_once_flag, CurlGlobalInit_ThreadSafe);

    curl = curl_easy_init();
    std::deque<char> s;

    std::string agent = GetUserAgent();
    if (curl) {

        CurlCleaner cleaner(curl);

        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, agent.c_str());
        if (IncludeProgressBar) {
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
            curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, CurlProgress_CallbackFunc);
        } else {
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
        }
        // curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //verbose output
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK) {
            std::string errorMsg(curl_easy_strerror(res));
            throw std::runtime_error(std::string(errorMsg).c_str());
        } else {
            long http_response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
            if (http_response_code != 200) {
                throw std::runtime_error("Error retrieving data with https protocol from URL \"" + URL +
                                         "\", error code: " + ToString(http_response_code) +
                                         ". Probably the URL is invalid.");
            }
        }

        /* always cleanup */
        // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
        // curl_easy_cleanup(curl);
    }
    std::string fileStr(s.begin(), s.end());
    return fileStr;
}

std::string cURLTools::PostJsonToHTTPS(const std::string& URL, long ConnectionTimeout,
                                       const std::string& readdata, bool chunked)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
    boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
    boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0,
                     static_cast<const ossl_init_settings_st*>(NULL));
#endif

    CURL*    curl;
    CURLcode res;

    boost::call_once(init_curl_global_once_flag, CurlGlobalInit_ThreadSafe);

    /* get a curl handle */
    curl = curl_easy_init();
    std::deque<char> writedata;
    std::string      agent = GetUserAgent();
    if (curl) {

        CurlCleaner cleaner(curl);

        struct curl_slist* headers = NULL;

        /* First set the URL that is about to receive our POST. This URL can
         just as well be a https:// URL if that is what should receive the
         data. */
        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        //        curl_easy_setopt(curl, CURLOPT_READDATA, &readdata);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writedata);
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, CurlRead_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
        /* Now specify the POST data */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, readdata.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, agent.c_str());

        headers = curl_slist_append(headers, "Content-Type: application/json");
        headers = curl_slist_append(headers, "charsets: utf-8");

        // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // verbose output
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);
        if (chunked) {

            headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
            /* use curl_slist_free_all() after the *perform() call to free this
         list again */
        } else {
            /* Set the expected POST size. If you want to POST large amounts of data,
       consider CURLOPT_POSTFIELDSIZE_LARGE */
            curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)readdata.size());
        }

        /*
              Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue"
              header.  You can disable this header with CURLOPT_HTTPHEADER as usual.
              NOTE: if you want chunked transfer too, you need to combine these two
              since you can only set one list of headers with CURLOPT_HTTPHEADER. */

        /* A less good option would be to enforce HTTP 1.0, but that might also
               have other implications. */
        const bool disable_expect = false;
        if (disable_expect) {
            headers = curl_slist_append(headers, "Expect:");
            /* use curl_slist_free_all() after the *perform() call to free this
                 list again */
        }

        res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK) {
            std::string errorMsg(curl_easy_strerror(res));
            throw std::runtime_error(std::string(errorMsg).c_str());
        } else {
            long http_response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
            if (http_response_code != 200) {
                json_spirit::Value errorData;
                if (json_spirit::read(std::string(writedata.begin(), writedata.end()), errorData)) {
                    json_spirit::Value errorMsg;
                    errorMsg = json_spirit::find_value(errorData.get_obj(), "message");
                    throw std::runtime_error("Failed to create transaction with error: " +
                                             errorMsg.get_str());
                } else {
                    throw std::runtime_error("Error posting data with https protocol from URL \"" + URL +
                                             "\", error code: " + ToString(http_response_code) +
                                             ". Probably the URL is invalid. Could not retrieve more "
                                             "information on the error.");
                }
            }
        }

        /* always cleanup */
        // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
        // curl_easy_cleanup(curl);
    }
    std::string fileStr(writedata.begin(), writedata.end());
    return fileStr;
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                    OpenSim:  PSimTool.cpp                                  *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2014 Stanford University and the Authors                *
 * Author(s): Chris Dembia                                                    *
 *                                                                            *
 * 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 "PSimTool.h"

#include "PSimDynamicOptimizationSolver.h"
#include "StatesCollector.h"
#include "StateTrajectory.h"

#include <OpenSim/Simulation/Manager/Manager.h>

namespace OpenSim {

PSimTool::PSimTool()
{
    constructProperties();
}

PSimTool::PSimTool(const std::string& fileName)
    : Object(fileName, false)
{
    constructProperties();
    updateFromXMLDocument();
    checkForUnusedInitialGuesses();
    if (!get_base_model_file().empty()) {
        m_model.reset(new Model(getAbsolutePathname(get_base_model_file())));
    }
}

void PSimTool::constructProperties() {

    constructProperty_base_model_file("");
    constructProperty_solver(PSimDynamicOptimizationSolver());

    constructProperty_results_dir("");
    constructProperty_initial_time(0);
    constructProperty_final_time(1);
    constructProperty_visualize(false);

    constructProperty_parameters();
    constructProperty_goals();

    PSimParameterValueSet initial_guess;
    constructProperty_initial_guess(initial_guess);

}

unsigned int PSimTool::numOptimizerParameters() const
{
    unsigned int sum = 0;
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        if (param.get_apply() && param.get_optimize()) {
            sum += get_parameters(itp).numScalarParameters();
        }
    }
    return sum;
}

void PSimTool::applyParametersToModel(const PSimParameterValueSet& paramValues,
        Model& model) const
{
    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        // If we should pay attention to this parameter.
        if (param.get_apply()) {
            // If the parameter is to be optimized.
            if (param.get_optimize()) {
                const double value = paramValues.get(param.getName()).get_value();
                param.applyToModel(value, model);
            }
            else {
                // Use the default value of the parameter.
                // TODO if we decide not to create a new copy of the model,
                // we don't need to do this after the first call.
                param.applyToModel(param.get_default_value(), model);
            }
        }
    }
}

void PSimTool::applyParametersToInitState(
        const PSimParameterValueSet& paramValues,
        const Model& model, SimTK::State& initState) const
{
    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        // If we should pay attention to this parameter.
        if (param.get_apply()) {
            // If the parameter is to be optimized.
            if (param.get_optimize()) {
                const double value = paramValues.get(param.getName()).get_value();
                param.applyToInitialState(value, model, initState);
            }
            else {
                // Use the default value of the parameter.
                // TODO if we decide not to create a new copy of the model,
                // we don't need to do this after the first call.
                param.applyToInitialState(param.get_default_value(), model,
                        initState);
            }
        }
    }
}

void PSimTool::applyParametersToStateCache(
        const PSimParameterValueSet& paramValues,
        const Model& model, const SimTK::State& s) const
{
    // TODO this could be costly?
    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        // If we should pay attention to this parameter.
        if (param.get_apply()) {
            // If the parameter is to be optimized.
            if (param.get_optimize()) {
                const double value = paramValues.get(param.getName()).get_value();
                param.applyToStateCache(value, model, s);
            }
            else {
                // Use the default value of the parameter.
                // TODO if we decide not to create a new copy of the model,
                // we don't need to do this after the first call.
                param.applyToStateCache(param.get_default_value(), model, s);
            }
        }
    }
}

void PSimTool::initialOptimizerParameterValuesAndLimits(
        SimTK::Vector& initOptParams,
        SimTK::Vector& lowerLimits,
        SimTK::Vector& upperLimits) const
{
    initOptParams.resize(numOptimizerParameters());
    lowerLimits.resize(numOptimizerParameters());
    upperLimits.resize(numOptimizerParameters());

    // Indexes through optimizer parameters.
    unsigned int iop = 0;

    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter& param = get_parameters(itp);
        // If the parameter is to be optimized.
        if (param.get_apply() && param.get_optimize()) {
            // Ignore values in initial_guess for parameters that are not
            // set to be optimized.

            double unnormalized;

            // The user supplied an initial guess.
            if (get_initial_guess().contains(param.getName())) {
                const PSimParameterValue& pval =
                        get_initial_guess().get(param.getName());
                unnormalized = pval.get_value();
            }
            else {
                unnormalized = param.get_default_value();
            }

            // Normalize the parameter, place it in the initial opt. params.
            initOptParams[iop] = param.normalized(unnormalized);

            // Normalize the lower and upper limits.
            lowerLimits[iop] = param.normalized(param.get_lower_limit());
            upperLimits[iop] = param.normalized(param.get_upper_limit());

            iop++;
        }
    }
}

PSimParameterValueSet PSimTool::solve() const
{
    // TODO print the updated model?
    // TODO print the objective values (at each iteration?)
    return get_solver().solve(*this);
}

double PSimTool::simulate(const PSimParameterValueSet& pvalset) const
{
    // Initialize model and apply model parameters.
    // ============================================
    // Create a copy of the base model.
    Model model(getBaseModel());
    if (get_visualize()) model.setUseVisualizer(true);
    applyParametersToModel(pvalset, model);

    // Add PSimGoal's to Model as ModelComponents. Do this after applying the
    // parameters, as the goals may depend on the effect of parameters.
    const auto goals = addGoalsToModel(model);

    // Mechanism to record the trajectory of successful states.
    // --------------------------------------------------------
    StatesCollector* statesCollector = new StatesCollector();
    statesCollector->setName("statesCollector");
    model.addAnalysis(statesCollector);

    // Generate an initial state. Must also be done after applying to model.
    SimTK::State& state = model.initSystem();

    // Now that the model is finalized for this sim., modify initial state.
    // ====================================================================
    applyParametersToInitState(pvalset, model, state);

    // Simulate.
    // =========
    SimTK::RungeKuttaMersonIntegrator integrator(model.getSystem());
    OpenSim::Manager manager(model, integrator);
    manager.setWriteToStorage(false);
    manager.setInitialTime(get_initial_time());
    manager.setFinalTime(get_final_time());
    manager.integrate(state);

    // Compute objective function value with the goals.
    // ================================================
    const StateTrajectory& states = statesCollector->getStateTrajectory();
    return evaluateGoals(goals, pvalset, states);
}

PSimParameterValueSet PSimTool::createParameterValueSet(
        const SimTK::Vector &optParamValues) const
{
    // TODO will have to change if the solver adds its own parameters.
    PSimParameterValueSet pvalset;

    // Indexes through optimizer parameters.
    unsigned int iop = 0;

    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {

        const PSimParameter& param = get_parameters(itp);

        // If the parameter was optimized.
        if (param.get_apply() && param.get_optimize()) {
            PSimParameterValue* pval = new PSimParameterValue();
            pval->setName(param.getName());
            // TODO get subvector.
            pval->set_value(param.unnormalized(optParamValues[iop]));
            pvalset.adoptAndAppend(pval);
            // TODO increase index by #scalar parameters.
            iop++;
        }
    }
    return pvalset;
}

void PSimTool::checkForUnusedInitialGuesses() const {
    for (unsigned int ig = 0; ig < get_initial_guess().getSize(); ++ig) {

        const PSimParameterValue& initialGuess = get_initial_guess().get(ig);
        bool unused = true;
        for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp)
        {
            const PSimParameter& param = get_parameters(itp);
            if (initialGuess.getName() == param.getName()) {
                unused = false;
                break;
            }
        }

        if (unused) {
            // TODO make this into a warning. TODO test this.
            throw OpenSim::Exception("Initial guess '" + initialGuess.getName()
                    + "' does not match any parameter.");
        }
    }
}

std::vector<const PSimGoal*> PSimTool::addGoalsToModel(Model& model) const
{
    std::vector<const PSimGoal*> goals;
    for (unsigned int ig = 0; ig < getProperty_goals().size(); ++ig) {
        const PSimGoal& goal = get_goals(ig);
        if (goal.get_enabled()) {
            PSimGoal* clone = goal.clone();
            // The model now owns this clone.
            model.addModelComponent(clone);
            // Append to the return vector.
            goals.push_back(clone);
        }
    }
    return goals;
}

SimTK::Real PSimTool::evaluateGoals(
        const std::vector<const PSimGoal*>& objectives,
        const PSimParameterValueSet& pvalset,
        const StateTrajectory& states)
{
    SimTK::Real f = 0;
    for (auto obj : objectives) {
        if (obj->get_enabled()) {
        // TODO move enabled check to PSimGoal.
            f += obj->get_weight() * obj->evaluate(pvalset, states);
        }
    }
    return f;
}

} // namespace OpenSim

<commit_msg>Initial guesses checked before solving.<commit_after>/* -------------------------------------------------------------------------- *
 *                    OpenSim:  PSimTool.cpp                                  *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2014 Stanford University and the Authors                *
 * Author(s): Chris Dembia                                                    *
 *                                                                            *
 * 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 "PSimTool.h"

#include "PSimDynamicOptimizationSolver.h"
#include "StatesCollector.h"
#include "StateTrajectory.h"

#include <OpenSim/Simulation/Manager/Manager.h>

namespace OpenSim {

PSimTool::PSimTool()
{
    constructProperties();
}

PSimTool::PSimTool(const std::string& fileName)
    : Object(fileName, false)
{
    constructProperties();
    updateFromXMLDocument();
    if (!get_base_model_file().empty()) {
        m_model.reset(new Model(getAbsolutePathname(get_base_model_file())));
    }
}

void PSimTool::constructProperties() {

    constructProperty_base_model_file("");
    constructProperty_solver(PSimDynamicOptimizationSolver());

    constructProperty_results_dir("");
    constructProperty_initial_time(0);
    constructProperty_final_time(1);
    constructProperty_visualize(false);

    constructProperty_parameters();
    constructProperty_goals();

    PSimParameterValueSet initial_guess;
    constructProperty_initial_guess(initial_guess);

}

unsigned int PSimTool::numOptimizerParameters() const
{
    unsigned int sum = 0;
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        if (param.get_apply() && param.get_optimize()) {
            sum += get_parameters(itp).numScalarParameters();
        }
    }
    return sum;
}

void PSimTool::applyParametersToModel(const PSimParameterValueSet& paramValues,
        Model& model) const
{
    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        // If we should pay attention to this parameter.
        if (param.get_apply()) {
            // If the parameter is to be optimized.
            if (param.get_optimize()) {
                const double value = paramValues.get(param.getName()).get_value();
                param.applyToModel(value, model);
            }
            else {
                // Use the default value of the parameter.
                // TODO if we decide not to create a new copy of the model,
                // we don't need to do this after the first call.
                param.applyToModel(param.get_default_value(), model);
            }
        }
    }
}

void PSimTool::applyParametersToInitState(
        const PSimParameterValueSet& paramValues,
        const Model& model, SimTK::State& initState) const
{
    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        // If we should pay attention to this parameter.
        if (param.get_apply()) {
            // If the parameter is to be optimized.
            if (param.get_optimize()) {
                const double value = paramValues.get(param.getName()).get_value();
                param.applyToInitialState(value, model, initState);
            }
            else {
                // Use the default value of the parameter.
                // TODO if we decide not to create a new copy of the model,
                // we don't need to do this after the first call.
                param.applyToInitialState(param.get_default_value(), model,
                        initState);
            }
        }
    }
}

void PSimTool::applyParametersToStateCache(
        const PSimParameterValueSet& paramValues,
        const Model& model, const SimTK::State& s) const
{
    // TODO this could be costly?
    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter & param = get_parameters(itp);
        // If we should pay attention to this parameter.
        if (param.get_apply()) {
            // If the parameter is to be optimized.
            if (param.get_optimize()) {
                const double value = paramValues.get(param.getName()).get_value();
                param.applyToStateCache(value, model, s);
            }
            else {
                // Use the default value of the parameter.
                // TODO if we decide not to create a new copy of the model,
                // we don't need to do this after the first call.
                param.applyToStateCache(param.get_default_value(), model, s);
            }
        }
    }
}

void PSimTool::initialOptimizerParameterValuesAndLimits(
        SimTK::Vector& initOptParams,
        SimTK::Vector& lowerLimits,
        SimTK::Vector& upperLimits) const
{
    initOptParams.resize(numOptimizerParameters());
    lowerLimits.resize(numOptimizerParameters());
    upperLimits.resize(numOptimizerParameters());

    // Indexes through optimizer parameters.
    unsigned int iop = 0;

    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {
        const PSimParameter& param = get_parameters(itp);
        // If the parameter is to be optimized.
        if (param.get_apply() && param.get_optimize()) {
            // Ignore values in initial_guess for parameters that are not
            // set to be optimized.

            double unnormalized;

            // The user supplied an initial guess.
            if (get_initial_guess().contains(param.getName())) {
                const PSimParameterValue& pval =
                        get_initial_guess().get(param.getName());
                unnormalized = pval.get_value();
            }
            else {
                unnormalized = param.get_default_value();
            }

            // Normalize the parameter, place it in the initial opt. params.
            initOptParams[iop] = param.normalized(unnormalized);

            // Normalize the lower and upper limits.
            lowerLimits[iop] = param.normalized(param.get_lower_limit());
            upperLimits[iop] = param.normalized(param.get_upper_limit());

            iop++;
        }
    }
}

PSimParameterValueSet PSimTool::solve() const
{
    checkForUnusedInitialGuesses();
    // TODO print the updated model?
    // TODO print the objective values (at each iteration?)
    return get_solver().solve(*this);
}

double PSimTool::simulate(const PSimParameterValueSet& pvalset) const
{
    // Initialize model and apply model parameters.
    // ============================================
    // Create a copy of the base model.
    Model model(getBaseModel());
    if (get_visualize()) model.setUseVisualizer(true);
    applyParametersToModel(pvalset, model);

    // Add PSimGoal's to Model as ModelComponents. Do this after applying the
    // parameters, as the goals may depend on the effect of parameters.
    const auto goals = addGoalsToModel(model);

    // Mechanism to record the trajectory of successful states.
    // --------------------------------------------------------
    StatesCollector* statesCollector = new StatesCollector();
    statesCollector->setName("statesCollector");
    model.addAnalysis(statesCollector);

    // Generate an initial state. Must also be done after applying to model.
    SimTK::State& state = model.initSystem();

    // Now that the model is finalized for this sim., modify initial state.
    // ====================================================================
    applyParametersToInitState(pvalset, model, state);

    // Simulate.
    // =========
    SimTK::RungeKuttaMersonIntegrator integrator(model.getSystem());
    OpenSim::Manager manager(model, integrator);
    manager.setWriteToStorage(false);
    manager.setInitialTime(get_initial_time());
    manager.setFinalTime(get_final_time());
    manager.integrate(state);

    // Compute objective function value with the goals.
    // ================================================
    const StateTrajectory& states = statesCollector->getStateTrajectory();
    return evaluateGoals(goals, pvalset, states);
}

PSimParameterValueSet PSimTool::createParameterValueSet(
        const SimTK::Vector &optParamValues) const
{
    // TODO will have to change if the solver adds its own parameters.
    PSimParameterValueSet pvalset;

    // Indexes through optimizer parameters.
    unsigned int iop = 0;

    // Indexes through tool parameters.
    for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp) {

        const PSimParameter& param = get_parameters(itp);

        // If the parameter was optimized.
        if (param.get_apply() && param.get_optimize()) {
            PSimParameterValue* pval = new PSimParameterValue();
            pval->setName(param.getName());
            // TODO get subvector.
            pval->set_value(param.unnormalized(optParamValues[iop]));
            pvalset.adoptAndAppend(pval);
            // TODO increase index by #scalar parameters.
            iop++;
        }
    }
    return pvalset;
}

void PSimTool::checkForUnusedInitialGuesses() const {
    for (unsigned int ig = 0; ig < get_initial_guess().getSize(); ++ig) {

        const PSimParameterValue& initialGuess = get_initial_guess().get(ig);
        bool unused = true;
        for (unsigned int itp = 0; itp < getProperty_parameters().size(); ++itp)
        {
            const PSimParameter& param = get_parameters(itp);
            if (initialGuess.getName() == param.getName()) {
                unused = false;
                break;
            }
        }

        if (unused) {
            // TODO make this into a warning. TODO test this.
            throw OpenSim::Exception("Initial guess '" + initialGuess.getName()
                    + "' does not match any parameter.");
        }
    }
}

std::vector<const PSimGoal*> PSimTool::addGoalsToModel(Model& model) const
{
    std::vector<const PSimGoal*> goals;
    for (unsigned int ig = 0; ig < getProperty_goals().size(); ++ig) {
        const PSimGoal& goal = get_goals(ig);
        if (goal.get_enabled()) {
            PSimGoal* clone = goal.clone();
            // The model now owns this clone.
            model.addModelComponent(clone);
            // Append to the return vector.
            goals.push_back(clone);
        }
    }
    return goals;
}

SimTK::Real PSimTool::evaluateGoals(
        const std::vector<const PSimGoal*>& objectives,
        const PSimParameterValueSet& pvalset,
        const StateTrajectory& states)
{
    SimTK::Real f = 0;
    for (auto obj : objectives) {
        if (obj->get_enabled()) {
        // TODO move enabled check to PSimGoal.
            f += obj->get_weight() * obj->evaluate(pvalset, states);
        }
    }
    return f;
}

} // namespace OpenSim

<|endoftext|>


<commit_before>//===-- Analysis/Writer.cpp - Printing routines for analyses -----*- C++ -*--=//
//
// This library file implements analysis result printing support for
// llvm/Analysis/Writer.h
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Writer.h"
#include "llvm/Analysis/IntervalPartition.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/InductionVariable.h"
#include "llvm/Assembly/Writer.h"
#include <iterator>
#include <algorithm>
#include <string>
using std::ostream;
using std::set;
using std::vector;
using std::string;

//===----------------------------------------------------------------------===//
//  Interval Printing Routines
//===----------------------------------------------------------------------===//

void WriteToOutput(const Interval *I, ostream &o) {
  o << "-------------------------------------------------------------\n"
       << "Interval Contents:\n";

  // Print out all of the basic blocks in the interval...
  copy(I->Nodes.begin(), I->Nodes.end(),
       std::ostream_iterator<BasicBlock*>(o, "\n"));

  o << "Interval Predecessors:\n";
  copy(I->Predecessors.begin(), I->Predecessors.end(),
       std::ostream_iterator<BasicBlock*>(o, "\n"));

  o << "Interval Successors:\n";
  copy(I->Successors.begin(), I->Successors.end(),
       std::ostream_iterator<BasicBlock*>(o, "\n"));
}

void WriteToOutput(const IntervalPartition &IP, ostream &o) {
  copy(IP.begin(), IP.end(), std::ostream_iterator<const Interval *>(o, "\n"));
}

//===----------------------------------------------------------------------===//
//  Dominator Printing Routines
//===----------------------------------------------------------------------===//

ostream &operator<<(ostream &o, const set<BasicBlock*> &BBs) {
  copy(BBs.begin(),BBs.end(), std::ostream_iterator<BasicBlock*>(o, "\n"));
  return o;
}

void WriteToOutput(const DominatorSet &DS, ostream &o) {
  for (DominatorSet::const_iterator I = DS.begin(), E = DS.end(); I != E; ++I) {
    o << "=============================--------------------------------\n"
      << "\nDominator Set For Basic Block\n" << I->first
      << "-------------------------------\n" << I->second << "\n";
  }
}

void WriteToOutput(const ImmediateDominators &ID, ostream &o) {
  for (ImmediateDominators::const_iterator I = ID.begin(), E = ID.end();
       I != E; ++I) {
    o << "=============================--------------------------------\n"
      << "\nImmediate Dominator For Basic Block\n" << I->first
      << "is: \n" << I->second << "\n";
  }
}

static ostream &operator<<(ostream &o, const DominatorTree::Node *Node) {
  return o << Node->getNode() << "\n------------------------------------------\n";

}

static void PrintDomTree(const DominatorTree::Node *N, ostream &o,
                         unsigned Lev) {
  o << "Level #" << Lev << ":  " << N;
  for (DominatorTree::Node::const_iterator I = N->begin(), E = N->end();
       I != E; ++I) {
    PrintDomTree(*I, o, Lev+1);
  }
}

void WriteToOutput(const DominatorTree &DT, ostream &o) {
  o << "=============================--------------------------------\n"
    << "Inorder Dominator Tree:\n";
  PrintDomTree(DT[DT.getRoot()], o, 1);
}

void WriteToOutput(const DominanceFrontier &DF, ostream &o) {
  for (DominanceFrontier::const_iterator I = DF.begin(), E = DF.end();
       I != E; ++I) {
    o << "=============================--------------------------------\n"
      << "\nDominance Frontier For Basic Block\n" << I->first
      << "is: \n" << I->second << "\n";
  }
}

//===----------------------------------------------------------------------===//
//  Loop Printing Routines
//===----------------------------------------------------------------------===//

void WriteToOutput(const Loop *L, ostream &o) {
  o << string(L->getLoopDepth()*2, ' ') << "Loop Containing: ";

  for (unsigned i = 0; i < L->getBlocks().size(); ++i) {
    if (i) o << ",";
    WriteAsOperand(o, (const Value*)L->getBlocks()[i]);
  }
  o << "\n";

  copy(L->getSubLoops().begin(), L->getSubLoops().end(),
       std::ostream_iterator<const Loop*>(o, "\n"));
}

void WriteToOutput(const LoopInfo &LI, ostream &o) {
  copy(LI.getTopLevelLoops().begin(), LI.getTopLevelLoops().end(),
       std::ostream_iterator<const Loop*>(o, "\n"));
}

//===----------------------------------------------------------------------===//
//  Induction Variable Printing Routines
//===----------------------------------------------------------------------===//

void WriteToOutput(const InductionVariable &IV, ostream &o) {
  switch (IV.InductionType) {
  case InductionVariable::Cannonical:   o << "Cannonical ";   break;
  case InductionVariable::SimpleLinear: o << "SimpleLinear "; break;
  case InductionVariable::Linear:       o << "Linear ";       break;
  case InductionVariable::Unknown:      o << "Unrecognized "; break;
  }
  o << "Induction Variable";
  if (IV.Phi) {
    WriteAsOperand(o, (const Value*)IV.Phi);
    o << ":\n" << (const Value*)IV.Phi;
  } else {
    o << "\n";
  }
  if (IV.InductionType == InductionVariable::Unknown) return;

  o << "  Start ="; WriteAsOperand(o, IV.Start);
  o << "  Step =" ; WriteAsOperand(o, IV.Step);
  o << "\n";
}
<commit_msg>Print out post dominance data structures more nicely<commit_after>//===-- Analysis/Writer.cpp - Printing routines for analyses -----*- C++ -*--=//
//
// This library file implements analysis result printing support for
// llvm/Analysis/Writer.h
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Writer.h"
#include "llvm/Analysis/IntervalPartition.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/InductionVariable.h"
#include "llvm/Assembly/Writer.h"
#include <iterator>
#include <algorithm>
#include <string>
using std::ostream;
using std::set;
using std::vector;
using std::string;

//===----------------------------------------------------------------------===//
//  Interval Printing Routines
//===----------------------------------------------------------------------===//

void WriteToOutput(const Interval *I, ostream &o) {
  o << "-------------------------------------------------------------\n"
       << "Interval Contents:\n";

  // Print out all of the basic blocks in the interval...
  copy(I->Nodes.begin(), I->Nodes.end(),
       std::ostream_iterator<BasicBlock*>(o, "\n"));

  o << "Interval Predecessors:\n";
  copy(I->Predecessors.begin(), I->Predecessors.end(),
       std::ostream_iterator<BasicBlock*>(o, "\n"));

  o << "Interval Successors:\n";
  copy(I->Successors.begin(), I->Successors.end(),
       std::ostream_iterator<BasicBlock*>(o, "\n"));
}

void WriteToOutput(const IntervalPartition &IP, ostream &o) {
  copy(IP.begin(), IP.end(), std::ostream_iterator<const Interval *>(o, "\n"));
}

//===----------------------------------------------------------------------===//
//  Dominator Printing Routines
//===----------------------------------------------------------------------===//

ostream &operator<<(ostream &o, const set<BasicBlock*> &BBs) {
  for (set<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
       I != E; ++I) {
    o << "  ";
    WriteAsOperand(o, (Value*)*I, false);
    o << "\n";
   }
  return o;
}

void WriteToOutput(const DominatorSet &DS, ostream &o) {
  for (DominatorSet::const_iterator I = DS.begin(), E = DS.end(); I != E; ++I) {
    o << "=============================--------------------------------\n"
      << "\nDominator Set For Basic Block\n" << I->first
      << "-------------------------------\n" << I->second << "\n";
  }
}

void WriteToOutput(const ImmediateDominators &ID, ostream &o) {
  for (ImmediateDominators::const_iterator I = ID.begin(), E = ID.end();
       I != E; ++I) {
    o << "=============================--------------------------------\n"
      << "\nImmediate Dominator For Basic Block\n" << I->first
      << "is: \n" << I->second << "\n";
  }
}

static ostream &operator<<(ostream &o, const DominatorTree::Node *Node) {
  return o << Node->getNode() << "\n------------------------------------------\n";

}

static void PrintDomTree(const DominatorTree::Node *N, ostream &o,
                         unsigned Lev) {
  o << "Level #" << Lev << ":  " << N;
  for (DominatorTree::Node::const_iterator I = N->begin(), E = N->end();
       I != E; ++I) {
    PrintDomTree(*I, o, Lev+1);
  }
}

void WriteToOutput(const DominatorTree &DT, ostream &o) {
  o << "=============================--------------------------------\n"
    << "Inorder Dominator Tree:\n";
  PrintDomTree(DT[DT.getRoot()], o, 1);
}

void WriteToOutput(const DominanceFrontier &DF, ostream &o) {
  for (DominanceFrontier::const_iterator I = DF.begin(), E = DF.end();
       I != E; ++I) {
    o << "=============================--------------------------------\n"
      << "\nDominance Frontier For Basic Block\n";
    WriteAsOperand(o, (Value*)I->first, false);
    o << " is: \n" << I->second << "\n";
  }
}

//===----------------------------------------------------------------------===//
//  Loop Printing Routines
//===----------------------------------------------------------------------===//

void WriteToOutput(const Loop *L, ostream &o) {
  o << string(L->getLoopDepth()*2, ' ') << "Loop Containing: ";

  for (unsigned i = 0; i < L->getBlocks().size(); ++i) {
    if (i) o << ",";
    WriteAsOperand(o, (const Value*)L->getBlocks()[i]);
  }
  o << "\n";

  copy(L->getSubLoops().begin(), L->getSubLoops().end(),
       std::ostream_iterator<const Loop*>(o, "\n"));
}

void WriteToOutput(const LoopInfo &LI, ostream &o) {
  copy(LI.getTopLevelLoops().begin(), LI.getTopLevelLoops().end(),
       std::ostream_iterator<const Loop*>(o, "\n"));
}

//===----------------------------------------------------------------------===//
//  Induction Variable Printing Routines
//===----------------------------------------------------------------------===//

void WriteToOutput(const InductionVariable &IV, ostream &o) {
  switch (IV.InductionType) {
  case InductionVariable::Cannonical:   o << "Cannonical ";   break;
  case InductionVariable::SimpleLinear: o << "SimpleLinear "; break;
  case InductionVariable::Linear:       o << "Linear ";       break;
  case InductionVariable::Unknown:      o << "Unrecognized "; break;
  }
  o << "Induction Variable";
  if (IV.Phi) {
    WriteAsOperand(o, (const Value*)IV.Phi);
    o << ":\n" << (const Value*)IV.Phi;
  } else {
    o << "\n";
  }
  if (IV.InductionType == InductionVariable::Unknown) return;

  o << "  Start ="; WriteAsOperand(o, IV.Start);
  o << "  Step =" ; WriteAsOperand(o, IV.Step);
  o << "\n";
}
<|endoftext|>


<commit_before>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// Copyright (c) 2011, Robin Burchell
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>

#include <QDebug>
#include <QProcess>
#include <QFile>
#include <QDir>
#include <QSettings>
#include <mlite/mdesktopentry.h>

#ifdef HAVE_CONTENTACTION
#include <contentaction.h>
#endif

#include "launcheritem.h"

// Define this if you'd like to see debug messages from the launcher
#ifdef DEBUG_LAUNCHER
#define LAUNCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define LAUNCHER_DEBUG(things)
#endif

static QString findIconHelper(const QString &pathName, const QString &icon)
{
    QStringList extensions;
    extensions << "";
    extensions << ".png";
    extensions << ".svg";
    //    qDebug() << "Trying " << pathName << " for " << icon;

    foreach (const QString &extension, extensions) {
        if (QFile::exists(pathName + QDir::separator() + icon + extension))
            return pathName + QDir::separator() + icon + extension;
    }

    QStringList entryList = QDir(pathName).entryList(QStringList(), QDir::AllDirs | QDir::NoDotAndDotDot);
    foreach (const QString &dir, entryList) {
        QString retval = findIconHelper(QDir(pathName).absoluteFilePath(dir), icon);
        if (!retval.isNull())
            return retval;
    }

    // all else failed
    return QString();
}

static QString getIconPath(const QString &name)
{
    if (QFile::exists(name)) {
        // fast path: file given
        return name;
    }

    QSettings settings("MeeGo", "IconCache");
    QString cachedPath = settings.value(name).toString();

    if (!QFile::exists(cachedPath))
    {
        LAUNCHER_DEBUG("Negative cache hit for " << name << " to " << cachedPath);
    }
    else
    {
        return cachedPath;
    }

    QStringList themes = QDir("/usr/share/themes").entryList(QStringList(), QDir::AllDirs | QDir::NoDotAndDotDot);

    if (!themes.isEmpty())
    {
        // TODO: look up active theme in gconf and set it to the first search path, don't hardcode it.
        // TODO: would be nice to investigate if our fallback behaviour is actually correct, too, but meh.

        if (themes.contains("n900de") && themes.at(0) != "n900de")
        {
            themes.removeAll("n900de");
            themes.insert(0, "n900de");
        }

        foreach (const QString &theme, themes)
        {
            QString retval = findIconHelper("/usr/share/themes/" + theme, name);

            if (!retval.isNull())
            {
                if (QFile::exists(retval))
                {
                    settings.setValue(name, retval);
                    return retval;
                }
            }
        }
    }

    // they also seem to get plonked here
    QString retval = findIconHelper("/usr/share/pixmaps/", name);

    if (!retval.isNull())
    {
        if (QFile::exists(retval))
        {
            settings.setValue(name, retval);
            return retval;
        }
    }

    // I hate all application developers
    retval = findIconHelper("/usr/share/icons/hicolor/64x64/", name);

    if (!retval.isNull())
    {
        if (QFile::exists(retval))
        {
            settings.setValue(name, retval);
            return retval;
        }
    }

    return QString();
}

LauncherItem::LauncherItem(const QString &path, QObject *parent)
    : QObject(parent),
      _desktopEntry(new MDesktopEntry(path))
{
    emit this->itemChanged();
}

LauncherItem::~LauncherItem()
{
}

QString LauncherItem::filePath() const
{
    return _desktopEntry->fileName();
}

QString LauncherItem::title() const
{
    return _desktopEntry->name();
}

QString LauncherItem::entryType() const
{
    return _desktopEntry->type();
}

QString LauncherItem::iconFilePath() const
{
    return "file://" + getIconPath(_desktopEntry->icon());
}

QStringList LauncherItem::desktopCategories() const
{
    return _desktopEntry->categories();
}

bool LauncherItem::shouldDisplay() const
{
    return !_desktopEntry->noDisplay();
}

bool LauncherItem::isValid() const
{
    return _desktopEntry->isValid();
}

void LauncherItem::launchApplication() const
{
#if defined(HAVE_CONTENTACTION)
    LAUNCHER_DEBUG("launching content action for" << _desktopEntry->name());
    ContentAction::Action action = ContentAction::Action::launcherAction(_desktopEntry, QStringList());
    action.trigger();
#else
    LAUNCHER_DEBUG("launching exec line for" << _desktopEntry->name());

    // Get the command text from the desktop entry
    QString commandText = _desktopEntry->exec();

    // Take care of the freedesktop standards things

    commandText.replace(QRegExp("%k"), filePath());
    commandText.replace(QRegExp("%c"), _desktopEntry->name());
    commandText.remove(QRegExp("%[fFuU]"));

    if (!_desktopEntry->icon().isEmpty())
        commandText.replace(QRegExp("%i"), QString("--icon ") + _desktopEntry->icon());

    // DETAILS: http://standards.freedesktop.org/desktop-entry-spec/latest/index.html
    // DETAILS: http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html

    // Launch the application
    QProcess::startDetached(commandText);
#endif
}
<commit_msg>Desktop entries without an icon path will return an empty string as icon path.<commit_after>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// Copyright (c) 2011, Robin Burchell
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>

#include <QDebug>
#include <QProcess>
#include <QFile>
#include <QDir>
#include <QSettings>
#include <mlite/mdesktopentry.h>

#ifdef HAVE_CONTENTACTION
#include <contentaction.h>
#endif

#include "launcheritem.h"

// Define this if you'd like to see debug messages from the launcher
#ifdef DEBUG_LAUNCHER
#define LAUNCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define LAUNCHER_DEBUG(things)
#endif

static QString findIconHelper(const QString &pathName, const QString &icon)
{
    QStringList extensions;
    extensions << "";
    extensions << ".png";
    extensions << ".svg";
    //    qDebug() << "Trying " << pathName << " for " << icon;

    foreach (const QString &extension, extensions) {
        if (QFile::exists(pathName + QDir::separator() + icon + extension))
            return pathName + QDir::separator() + icon + extension;
    }

    QStringList entryList = QDir(pathName).entryList(QStringList(), QDir::AllDirs | QDir::NoDotAndDotDot);
    foreach (const QString &dir, entryList) {
        QString retval = findIconHelper(QDir(pathName).absoluteFilePath(dir), icon);
        if (!retval.isNull())
            return retval;
    }

    // all else failed
    return QString();
}

static QString getIconPath(const QString &name)
{
    if (QFile::exists(name)) {
        // fast path: file given
        return name;
    }

    QSettings settings("MeeGo", "IconCache");
    QString cachedPath = settings.value(name).toString();

    if (!QFile::exists(cachedPath))
    {
        LAUNCHER_DEBUG("Negative cache hit for " << name << " to " << cachedPath);
    }
    else
    {
        return cachedPath;
    }

    QStringList themes = QDir("/usr/share/themes").entryList(QStringList(), QDir::AllDirs | QDir::NoDotAndDotDot);

    if (!themes.isEmpty())
    {
        // TODO: look up active theme in gconf and set it to the first search path, don't hardcode it.
        // TODO: would be nice to investigate if our fallback behaviour is actually correct, too, but meh.

        if (themes.contains("n900de") && themes.at(0) != "n900de")
        {
            themes.removeAll("n900de");
            themes.insert(0, "n900de");
        }

        foreach (const QString &theme, themes)
        {
            QString retval = findIconHelper("/usr/share/themes/" + theme, name);

            if (!retval.isNull())
            {
                if (QFile::exists(retval))
                {
                    settings.setValue(name, retval);
                    return retval;
                }
            }
        }
    }

    // they also seem to get plonked here
    QString retval = findIconHelper("/usr/share/pixmaps/", name);

    if (!retval.isNull())
    {
        if (QFile::exists(retval))
        {
            settings.setValue(name, retval);
            return retval;
        }
    }

    // I hate all application developers
    retval = findIconHelper("/usr/share/icons/hicolor/64x64/", name);

    if (!retval.isNull())
    {
        if (QFile::exists(retval))
        {
            settings.setValue(name, retval);
            return retval;
        }
    }

    return QString();
}

LauncherItem::LauncherItem(const QString &path, QObject *parent)
    : QObject(parent),
      _desktopEntry(new MDesktopEntry(path))
{
    emit this->itemChanged();
}

LauncherItem::~LauncherItem()
{
}

QString LauncherItem::filePath() const
{
    return _desktopEntry->fileName();
}

QString LauncherItem::title() const
{
    return _desktopEntry->name();
}

QString LauncherItem::entryType() const
{
    return _desktopEntry->type();
}

QString LauncherItem::iconFilePath() const
{
    LAUNCHER_DEBUG("icon path is:" << _desktopEntry->icon());

    if (_desktopEntry->icon().length() == 0)
        return QString();

    return "file://" + getIconPath(_desktopEntry->icon());
}

QStringList LauncherItem::desktopCategories() const
{
    return _desktopEntry->categories();
}

bool LauncherItem::shouldDisplay() const
{
    return !_desktopEntry->noDisplay();
}

bool LauncherItem::isValid() const
{
    return _desktopEntry->isValid();
}

void LauncherItem::launchApplication() const
{
#if defined(HAVE_CONTENTACTION)
    LAUNCHER_DEBUG("launching content action for" << _desktopEntry->name());
    ContentAction::Action action = ContentAction::Action::launcherAction(_desktopEntry, QStringList());
    action.trigger();
#else
    LAUNCHER_DEBUG("launching exec line for" << _desktopEntry->name());

    // Get the command text from the desktop entry
    QString commandText = _desktopEntry->exec();

    // Take care of the freedesktop standards things

    commandText.replace(QRegExp("%k"), filePath());
    commandText.replace(QRegExp("%c"), _desktopEntry->name());
    commandText.remove(QRegExp("%[fFuU]"));

    if (!_desktopEntry->icon().isEmpty())
        commandText.replace(QRegExp("%i"), QString("--icon ") + _desktopEntry->icon());

    // DETAILS: http://standards.freedesktop.org/desktop-entry-spec/latest/index.html
    // DETAILS: http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html

    // Launch the application
    QProcess::startDetached(commandText);
#endif
}
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef CLUSTERING_ADMINISTRATION_MAIN_VERSION_CHECK_HPP_
#define CLUSTERING_ADMINISTRATION_MAIN_VERSION_CHECK_HPP_

#include <functional>

#include "errors.hpp"
#include <boost/shared_ptr.hpp>

#include "arch/runtime/coroutines.hpp"
#include "arch/timing.hpp"
#include "concurrency/auto_drainer.hpp"
#include "rdb_protocol/context.hpp"

struct http_result_t;

class cluster_semilattice_metadata_t;

enum class update_check_t {
    do_not_perform,
    perform,
};

class version_checker_t : private repeating_timer_callback_t {
public:
    typedef boost::shared_ptr<semilattice_readwrite_view_t
                              <cluster_semilattice_metadata_t> > metadata_ptr_t;
    version_checker_t(rdb_context_t *, version_checker_t::metadata_ptr_t,
                      const std::string &);
private:
    void do_check(bool is_initial, auto_drainer_t::lock_t keepalive);
    virtual void on_ring() {
        coro_t::spawn_sometime(std::bind(&version_checker_t::do_check,
                                         this, false, drainer.lock()));
    }
    void process_result(const http_result_t &);
    double cook(double);
    void report_weird(const std::string &msg);

    rdb_context_t *rdb_ctx;
    datum_string_t seen_version;
    version_checker_t::metadata_ptr_t metadata;
    std::string uname;
    auto_drainer_t drainer;
    repeating_timer_t timer;
};

#endif /* CLUSTERING_ADMINISTRATION_MAIN_VERSION_CHECK_HPP_ */
<commit_msg>Remove obsolete declaration.<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef CLUSTERING_ADMINISTRATION_MAIN_VERSION_CHECK_HPP_
#define CLUSTERING_ADMINISTRATION_MAIN_VERSION_CHECK_HPP_

#include <functional>

#include "errors.hpp"
#include <boost/shared_ptr.hpp>

#include "arch/runtime/coroutines.hpp"
#include "arch/timing.hpp"
#include "concurrency/auto_drainer.hpp"
#include "rdb_protocol/context.hpp"

struct http_result_t;

class cluster_semilattice_metadata_t;

enum class update_check_t {
    do_not_perform,
    perform,
};

class version_checker_t : private repeating_timer_callback_t {
public:
    typedef boost::shared_ptr<semilattice_readwrite_view_t
                              <cluster_semilattice_metadata_t> > metadata_ptr_t;
    version_checker_t(rdb_context_t *, version_checker_t::metadata_ptr_t,
                      const std::string &);
private:
    void do_check(bool is_initial, auto_drainer_t::lock_t keepalive);
    virtual void on_ring() {
        coro_t::spawn_sometime(std::bind(&version_checker_t::do_check,
                                         this, false, drainer.lock()));
    }
    void process_result(const http_result_t &);
    double cook(double);

    rdb_context_t *rdb_ctx;
    datum_string_t seen_version;
    version_checker_t::metadata_ptr_t metadata;
    std::string uname;
    auto_drainer_t drainer;
    repeating_timer_t timer;
};

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