<commit_before>/** eval-table.cc ---
 *
 * Copyright (C) 2011 OpenCog Foundation
 *
 * Author: Nil Geisweiller <nilg@desktop>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/trim.hpp>

#include <opencog/util/iostreamContainer.h>
#include <opencog/util/mt19937ar.h>
#include <opencog/util/numeric.h>

#include "eval-table.h"

using namespace boost::program_options;
using boost::lexical_cast;
using boost::trim;
using namespace opencog;

/**
 * Program to output the result of a combo program given input data
 * described in DSV format.
 */
static const pair<string, string> rand_seed_opt("random-seed", "r");
static const pair<string, string> input_table_opt("input-table", "i");
static const pair<string, string> target_feature_opt("target-feature", "u");
static const pair<string, string> ignore_feature_str_opt("ignore-feature", "Y");
static const pair<string, string> combo_str_opt("combo-program", "c");
static const pair<string, string> combo_prog_file_opt("combo-programs-file", "C");
static const pair<string, string> labels_opt("labels", "L");
static const pair<string, string> output_file_opt("output-file", "o");
static const pair<string, string> display_inputs_opt("display-inputs", "I");
static const pair<string, string> log_level_opt("log-level", "l");
static const pair<string, string> log_file_opt("log-file", "f");
static const string default_log_file_prefix = "eval-table";
static const string default_log_file_suffix = "log";
static const string default_log_file = default_log_file_prefix + "." + default_log_file_suffix;

/**
 * Convert a string representing a combo program in a combo_tree.
 *
 * @param combo_prog_str   the string containing the combo program
 * @param has_labels       true if the combo program has labels instead of
 * place holders (like and($start $up) instead of and($23 $134)
 * @param labels           a vector of labels
 * @return                 the combo_tree
 */
combo_tree str2combo_tree_label(const std::string& combo_prog_str,
                                bool has_labels,
                                const std::vector<std::string>& labels) {
    // combo pogram with place holders
    std::string combo_prog_ph_str =
        has_labels? l2ph(combo_prog_str, labels) : combo_prog_str;
    std::stringstream ss(combo_prog_ph_str);
    combo_tree tr;
    ss >> tr;
    return tr;
}

vector<string> get_all_combo_tree_str(const evalTableParameters& pa)
{
    vector<string> res(pa.combo_programs);     // from command line

    // from files
    for (const string& combo_programs_file : pa.combo_programs_files) {
        ifstream in(combo_programs_file.c_str());
        if (in) {
            while (in.good()) {
                string line;
                getline(in, line);
                if (line.empty())
                    continue;
                res += line;
            }
        } else {
            logger().error("Error: file %s can not be found.",
                           combo_programs_file.c_str());
            exit(1);
        }
    }

    return res;
}

void output_results(const evalTableParameters& pa,
                    const Table& table, const OTable& ot_tr,
                    const string output_file)
{
    if(output_file.empty())
        output_results(cout, pa, table, ot_tr);
    else {
        ofstream of(output_file.c_str());
        output_results(of, pa, table, ot_tr);
    }
}

void eval_output_results(const evalTableParameters& pa,
                         const Table& table, const vector<combo_tree>& trs)
{
    unsigned npad = ndigits(trs.size());
    OC_ASSERT(pa.output_files.size() == trs.size() || pa.output_files.size() <= 1);
    for (unsigned i = 0; i < trs.size(); i++) {
        // Evaluated tr over input table
        OTable ot_tr(trs[i], table.itable);
        if (!pa.target_feature_str.empty())
            ot_tr.set_label(pa.target_feature_str);
        // Determine output file name
        stringstream of_ss;
        if (pa.output_files.size() == 1) {
            of_ss << pa.output_files.front();
            if (trs.size() > 1 && pa.split_output)
                of_ss << setfill('0') << setw(npad) << i;
        }
        else if (pa.output_files.size() > 1)
            of_ss << pa.output_files[i];
        // Print results
        output_results(pa, table, ot_tr, of_ss.str());
    }
}

void read_eval_output_results(evalTableParameters& pa)
{
    ostreamContainer(logger().info() << "Ignore the following features: ",
                     pa.ignore_features_str);
    OC_ASSERT(std::find(pa.ignore_features_str.begin(),
              pa.ignore_features_str.end(),
              pa.target_feature_str)
              == pa.ignore_features_str.end(),
              "You cannot ignore the target feature %s",
              pa.target_feature_str.c_str());

    // get all combo tree strings (from command line and file)
    vector<string> all_combo_tree_str = get_all_combo_tree_str(pa);

    // parse all variables from all combo tree strings
    vector<string> all_variables;
    for (string combo_tree_str : all_combo_tree_str) {
        vector<string> vars = parse_combo_variables(combo_tree_str);
        all_variables.insert(all_variables.end(), vars.begin(), vars.end());
    }
    set<string> all_unique_variables(all_variables.begin(), all_variables.end());

    // HERE WE ARE ASSUMING THAT THE INPUT FILE HAS A HEADER!!!
// XXX FIXME
    vector<string> header = get_header(pa.input_table_file);

    // get (header - all_unique_variables - target feature)
    vector<string> ignore_variables;
    for (string f : header)
        if (f != pa.target_feature_str
            && all_unique_variables.find(f) == all_unique_variables.end())
        {
            ignore_variables += f;
            logger().debug() << "Table variable not in combo tree: " << f;
        }

    // read data ITable (using ignore_variables)
    Table table;
    if (pa.target_feature_str.empty()) {
        OC_ASSERT(pa.timestamp_feature_str.empty(),
                  "Timestamp feature not implemented. "
                  "You may specify a target feature, option -u, "
                  "as loadTable does support timestamp");
        table.itable = loadITable_optimized(pa.input_table_file,
                                            ignore_variables);
    }
    else {
        table = loadTable(pa.input_table_file, pa.target_feature_str,
                          pa.timestamp_feature_str, ignore_variables);
    }
    logger().debug() << "Done loading table from " << pa.input_table_file;

    ITable& it = table.itable;

    // parse combo programs
    vector<combo_tree> trs;
    for (const string& tr_str : all_combo_tree_str) {
        combo_tree tr = str2combo_tree_label(tr_str, pa.has_labels, it.get_labels());
        logger().fine() << "Combo str: " << tr_str << "\n";
        logger().debug() << "Parsed combo: " << tr;
        trs += tr;
    }

    // eval and output the results
    eval_output_results(pa, table, trs);
}

/**
 * Read and parse the eval-table program arguments.
 * Return the parsed results in the parameters struct.
 */
evalTableParameters eval_table_program_args(int argc, char** argv)
{
    // program options, see options_description below for their meaning
    evalTableParameters pa;
    unsigned long rand_seed;

    // Declare the supported options.
    options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "Produce help message.\n")

        (opt_desc_str(rand_seed_opt).c_str(),
         value<unsigned long>(&rand_seed)->default_value(1),
         "Random seed.\n")

        (opt_desc_str(input_table_opt).c_str(),
         value<string>(&pa.input_table_file),
         "Input table file in DSV format (seperators are comma, "
         "whitespace and tabulation).\n")

        (opt_desc_str(target_feature_opt).c_str(),
         value<string>(&pa.target_feature_str),
         "Target feature name. If empty (default) then no target feature "
         "is considered and the table is assumed to be all input data.\n")

        ("timestamp-feature",
         value<string>(&pa.timestamp_feature_str),
         "Label of the timestamp feature. If none is given it is ignored.\n")

        (opt_desc_str(ignore_feature_str_opt).c_str(),
         value<vector<string>>(&pa.ignore_features_str),
         "Ignore feature from the datasets. Can be used several times "
         "to ignore several features.\n")

        (opt_desc_str(combo_str_opt).c_str(),
         value<vector<string>>(&pa.combo_programs),
         "Combo program to evaluate against the input table. Note that in order "
         "to have variables not being interpreted as shell variables you may "
         "want to put the combi between single quotes. This option can be "
         "used several times so that several programs are evaluated at once.\n")

        (opt_desc_str(combo_prog_file_opt).c_str(),
         value<vector<string>>(&pa.combo_programs_files),
         "File containing combo programs to evaluate against the input table. "
         "Each combo program in the file is seperated by a new line and each "
         "results are displaied in the same order, seperated by a new line.\n")

        (opt_desc_str(labels_opt).c_str(),
         value<bool>(&pa.has_labels)->default_value(true),
         "If enabled then the combo program is expected to contain variables "
         "labels $labels1, etc, instead of place holders. For instance one "
         "provide the combo program 'and($large $tall)' instead of "
         "'and($24 $124)'. In such a case it is expected that the input data "
         "file contains the labels as first row. "
         "TODO could be detected automatically.\n")

        (opt_desc_str(output_file_opt).c_str(),
         value<vector<string>>(&pa.output_files),
         "File where to save the results. If empty then it outputs on "
         "the stdout. Can be used multiple times for multiple combo. "
         "In this case it overwrites --split-output and the number of "
         " output files must be identical to the number of combos.\n")

        ("split-output", value<bool>(&pa.split_output)->default_value(true),
         "If enabled, then if there are several combo programs the output file "
         "is used as prefix for writing multiple output files corresponding to "
         "each combo programs. In that case each output file name is appended "
         "a suffix of digits representing the index of the combo program "
         "(starting from 0). Suffixes are 0-padded to respect lexicographic "
         "order as well. If disabled, or if no output file is provided "
         "(stdout) all outputs are appended.\n")

        (opt_desc_str(display_inputs_opt).c_str(), value<bool>(&pa.display_inputs)->default_value(false),
         "Display all inputs (as well as the output), "
         "the feature order is preserved.\n")

        (opt_desc_str(log_level_opt).c_str(),
         value<string>(&pa.log_level)->default_value("INFO"),
         "Log level, possible levels are NONE, ERROR, WARN, INFO, "
         "DEBUG, FINE. Case does not matter.\n")

        (opt_desc_str(log_file_opt).c_str(),
         value<string>(&pa.log_file)->default_value(default_log_file),
         "File name where to write the log.\n")
        ;

    variables_map vm;
    store(parse_command_line(argc, argv, desc), vm);
    notify(vm);

    if (vm.count("help") || argc == 1) {
        cout << desc << "\n";
        exit(1);
    }

    // Remove old log_file before setting the new one.
    remove(pa.log_file.c_str());
    logger().setFilename(pa.log_file);
    trim(pa.log_level);
    Logger::Level level = logger().getLevelFromString(pa.log_level);
    if (level != Logger::BAD_LEVEL)
        logger().setLevel(level);
    else {
        cerr << "Error: Log level " << pa.log_level << " is incorrect (see --help)." << endl;
        exit(1);
    }
    logger().setBackTraceLevel(Logger::ERROR);

    // init random generator
    randGen().seed(rand_seed);

    return pa;
}

/**
 * Program to evaluate a combo program over a data set repsented as csv file.
 */
int main(int argc, char** argv)
{
    evalTableParameters pa = eval_table_program_args(argc, argv);
    read_eval_output_results(pa);
    return 0;
}
<commit_msg>Fix bug in eval-table (timestamp was counted as ignored variable)<commit_after>/** eval-table.cc ---
 *
 * Copyright (C) 2011 OpenCog Foundation
 *
 * Author: Nil Geisweiller <nilg@desktop>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/trim.hpp>

#include <opencog/util/iostreamContainer.h>
#include <opencog/util/mt19937ar.h>
#include <opencog/util/numeric.h>

#include "eval-table.h"

using namespace boost::program_options;
using boost::lexical_cast;
using boost::trim;
using namespace opencog;

/**
 * Program to output the result of a combo program given input data
 * described in DSV format.
 */
static const pair<string, string> rand_seed_opt("random-seed", "r");
static const pair<string, string> input_table_opt("input-table", "i");
static const pair<string, string> target_feature_opt("target-feature", "u");
static const pair<string, string> ignore_feature_str_opt("ignore-feature", "Y");
static const pair<string, string> combo_str_opt("combo-program", "c");
static const pair<string, string> combo_prog_file_opt("combo-programs-file", "C");
static const pair<string, string> labels_opt("labels", "L");
static const pair<string, string> output_file_opt("output-file", "o");
static const pair<string, string> display_inputs_opt("display-inputs", "I");
static const pair<string, string> log_level_opt("log-level", "l");
static const pair<string, string> log_file_opt("log-file", "f");
static const string default_log_file_prefix = "eval-table";
static const string default_log_file_suffix = "log";
static const string default_log_file = default_log_file_prefix + "." + default_log_file_suffix;

/**
 * Convert a string representing a combo program in a combo_tree.
 *
 * @param combo_prog_str   the string containing the combo program
 * @param has_labels       true if the combo program has labels instead of
 * place holders (like and($start $up) instead of and($23 $134)
 * @param labels           a vector of labels
 * @return                 the combo_tree
 */
combo_tree str2combo_tree_label(const std::string& combo_prog_str,
                                bool has_labels,
                                const std::vector<std::string>& labels) {
    // combo pogram with place holders
    std::string combo_prog_ph_str =
        has_labels? l2ph(combo_prog_str, labels) : combo_prog_str;
    std::stringstream ss(combo_prog_ph_str);
    combo_tree tr;
    ss >> tr;
    return tr;
}

vector<string> get_all_combo_tree_str(const evalTableParameters& pa)
{
    vector<string> res(pa.combo_programs);     // from command line

    // from files
    for (const string& combo_programs_file : pa.combo_programs_files) {
        ifstream in(combo_programs_file.c_str());
        if (in) {
            while (in.good()) {
                string line;
                getline(in, line);
                if (line.empty())
                    continue;
                res += line;
            }
        } else {
            logger().error("Error: file %s can not be found.",
                           combo_programs_file.c_str());
            exit(1);
        }
    }

    return res;
}

void output_results(const evalTableParameters& pa,
                    const Table& table, const OTable& ot_tr,
                    const string output_file)
{
    if(output_file.empty())
        output_results(cout, pa, table, ot_tr);
    else {
        ofstream of(output_file.c_str());
        output_results(of, pa, table, ot_tr);
    }
}

void eval_output_results(const evalTableParameters& pa,
                         const Table& table, const vector<combo_tree>& trs)
{
    unsigned npad = ndigits(trs.size());
    OC_ASSERT(pa.output_files.size() == trs.size() || pa.output_files.size() <= 1);
    for (unsigned i = 0; i < trs.size(); i++) {
        // Evaluated tr over input table
        OTable ot_tr(trs[i], table.itable);
        if (!pa.target_feature_str.empty())
            ot_tr.set_label(pa.target_feature_str);
        // Determine output file name
        stringstream of_ss;
        if (pa.output_files.size() == 1) {
            of_ss << pa.output_files.front();
            if (trs.size() > 1 && pa.split_output)
                of_ss << setfill('0') << setw(npad) << i;
        }
        else if (pa.output_files.size() > 1)
            of_ss << pa.output_files[i];
        // Print results
        output_results(pa, table, ot_tr, of_ss.str());
    }
}

void read_eval_output_results(evalTableParameters& pa)
{
    ostreamContainer(logger().info() << "Ignore the following features: ",
                     pa.ignore_features_str);
    OC_ASSERT(std::find(pa.ignore_features_str.begin(),
              pa.ignore_features_str.end(),
              pa.target_feature_str)
              == pa.ignore_features_str.end(),
              "You cannot ignore the target feature %s",
              pa.target_feature_str.c_str());

    // get all combo tree strings (from command line and file)
    vector<string> all_combo_tree_str = get_all_combo_tree_str(pa);

    // parse all variables from all combo tree strings
    vector<string> all_variables;
    for (string combo_tree_str : all_combo_tree_str) {
        vector<string> vars = parse_combo_variables(combo_tree_str);
        all_variables.insert(all_variables.end(), vars.begin(), vars.end());
    }
    set<string> all_unique_variables(all_variables.begin(), all_variables.end());

    // HERE WE ARE ASSUMING THAT THE INPUT FILE HAS A HEADER!!!
// XXX FIXME
    vector<string> header = get_header(pa.input_table_file);

    // Add to ignore_valuesget (header - all_unique_variables - target feature)
    vector<string> ignore_variables;
    for (string f : header)
        if (f != pa.target_feature_str
            && f != pa.timestamp_feature_str
            && all_unique_variables.find(f) == all_unique_variables.end())
        {
            ignore_variables += f;
            logger().debug() << "Table variable not in combo tree: " << f;
        }

    // read data ITable (using ignore_variables)
    Table table;
    if (pa.target_feature_str.empty()) {
        OC_ASSERT(pa.timestamp_feature_str.empty(),
                  "Timestamp feature not implemented. "
                  "You may specify a target feature, option -u, "
                  "as loadTable does support timestamp");
        table.itable = loadITable_optimized(pa.input_table_file,
                                            ignore_variables);
    }
    else {
        table = loadTable(pa.input_table_file, pa.target_feature_str,
                          pa.timestamp_feature_str, ignore_variables);
    }
    logger().debug() << "Done loading table from " << pa.input_table_file;

    ITable& it = table.itable;

    // parse combo programs
    vector<combo_tree> trs;
    for (const string& tr_str : all_combo_tree_str) {
        combo_tree tr = str2combo_tree_label(tr_str, pa.has_labels, it.get_labels());
        logger().fine() << "Combo str: " << tr_str << "\n";
        logger().debug() << "Parsed combo: " << tr;
        trs += tr;
    }

    // eval and output the results
    eval_output_results(pa, table, trs);
}

/**
 * Read and parse the eval-table program arguments.
 * Return the parsed results in the parameters struct.
 */
evalTableParameters eval_table_program_args(int argc, char** argv)
{
    // program options, see options_description below for their meaning
    evalTableParameters pa;
    unsigned long rand_seed;

    // Declare the supported options.
    options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "Produce help message.\n")

        (opt_desc_str(rand_seed_opt).c_str(),
         value<unsigned long>(&rand_seed)->default_value(1),
         "Random seed.\n")

        (opt_desc_str(input_table_opt).c_str(),
         value<string>(&pa.input_table_file),
         "Input table file in DSV format (seperators are comma, "
         "whitespace and tabulation).\n")

        (opt_desc_str(target_feature_opt).c_str(),
         value<string>(&pa.target_feature_str),
         "Target feature name. If empty (default) then no target feature "
         "is considered and the table is assumed to be all input data.\n")

        ("timestamp-feature",
         value<string>(&pa.timestamp_feature_str),
         "Label of the timestamp feature. If none is given it is ignored.\n")

        (opt_desc_str(ignore_feature_str_opt).c_str(),
         value<vector<string>>(&pa.ignore_features_str),
         "Ignore feature from the datasets. Can be used several times "
         "to ignore several features.\n")

        (opt_desc_str(combo_str_opt).c_str(),
         value<vector<string>>(&pa.combo_programs),
         "Combo program to evaluate against the input table. Note that in order "
         "to have variables not being interpreted as shell variables you may "
         "want to put the combi between single quotes. This option can be "
         "used several times so that several programs are evaluated at once.\n")

        (opt_desc_str(combo_prog_file_opt).c_str(),
         value<vector<string>>(&pa.combo_programs_files),
         "File containing combo programs to evaluate against the input table. "
         "Each combo program in the file is seperated by a new line and each "
         "results are displaied in the same order, seperated by a new line.\n")

        (opt_desc_str(labels_opt).c_str(),
         value<bool>(&pa.has_labels)->default_value(true),
         "If enabled then the combo program is expected to contain variables "
         "labels $labels1, etc, instead of place holders. For instance one "
         "provide the combo program 'and($large $tall)' instead of "
         "'and($24 $124)'. In such a case it is expected that the input data "
         "file contains the labels as first row. "
         "TODO could be detected automatically.\n")

        (opt_desc_str(output_file_opt).c_str(),
         value<vector<string>>(&pa.output_files),
         "File where to save the results. If empty then it outputs on "
         "the stdout. Can be used multiple times for multiple combo. "
         "In this case it overwrites --split-output and the number of "
         " output files must be identical to the number of combos.\n")

        ("split-output", value<bool>(&pa.split_output)->default_value(true),
         "If enabled, then if there are several combo programs the output file "
         "is used as prefix for writing multiple output files corresponding to "
         "each combo programs. In that case each output file name is appended "
         "a suffix of digits representing the index of the combo program "
         "(starting from 0). Suffixes are 0-padded to respect lexicographic "
         "order as well. If disabled, or if no output file is provided "
         "(stdout) all outputs are appended.\n")

        (opt_desc_str(display_inputs_opt).c_str(), value<bool>(&pa.display_inputs)->default_value(false),
         "Display all inputs (as well as the output), "
         "the feature order is preserved.\n")

        (opt_desc_str(log_level_opt).c_str(),
         value<string>(&pa.log_level)->default_value("INFO"),
         "Log level, possible levels are NONE, ERROR, WARN, INFO, "
         "DEBUG, FINE. Case does not matter.\n")

        (opt_desc_str(log_file_opt).c_str(),
         value<string>(&pa.log_file)->default_value(default_log_file),
         "File name where to write the log.\n")
        ;

    variables_map vm;
    store(parse_command_line(argc, argv, desc), vm);
    notify(vm);

    if (vm.count("help") || argc == 1) {
        cout << desc << "\n";
        exit(1);
    }

    // Remove old log_file before setting the new one.
    remove(pa.log_file.c_str());
    logger().setFilename(pa.log_file);
    trim(pa.log_level);
    Logger::Level level = logger().getLevelFromString(pa.log_level);
    if (level != Logger::BAD_LEVEL)
        logger().setLevel(level);
    else {
        cerr << "Error: Log level " << pa.log_level << " is incorrect (see --help)." << endl;
        exit(1);
    }
    logger().setBackTraceLevel(Logger::ERROR);

    // init random generator
    randGen().seed(rand_seed);

    return pa;
}

/**
 * Program to evaluate a combo program over a data set repsented as csv file.
 */
int main(int argc, char** argv)
{
    evalTableParameters pa = eval_table_program_args(argc, argv);
    read_eval_output_results(pa);
    return 0;
}
<|endoftext|>


<commit_before>//
// async_client.cpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/asio/ssl.hpp>
#include <fstream>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>

using namespace boost::archive::iterators;
using boost::asio::ip::tcp;

class client
{
public:
    client(boost::asio::io_service& io_service,
           const std::string& server, const std::string& path, const std::string& binaryImgStr)
            : resolver_(io_service),
              ctx(io_service, boost::asio::ssl::context::method::tlsv12_client),
              socket_(io_service, ctx)
    {
        SSL_set_tlsext_host_name(socket_.native_handle(),server.c_str());
        ctx.set_default_verify_paths();
        /*ctx.set_options(boost::asio::ssl::context::default_workarounds
                        | boost::asio::ssl::context::no_sslv2
                        | boost::asio::ssl::context::no_sslv3
                        | boost::asio::ssl::context::no_tlsv1
                        | boost::asio::ssl::context::no_tlsv1_1);*/
        //socket_.set_verify_mode(boost::asio::ssl::verify_none);
        //ctx.load_verify_file("ca.pem");
        std::string b64ImgStr = base64_encode(reinterpret_cast<const unsigned char*>(binaryImgStr.c_str()), binaryImgStr.length());
        // Form the request. We specify the "Connection: close" header so that the
        // server will close the socket after transmitting the response. This will
        // allow us to treat all data up until the EOF as the content.
        std::ostream request_stream(&request_);
        request_stream << "POST " << path << " HTTP/1.1\r\n";
        request_stream << "Host: " << server << "\r\n";
        request_stream << "content-type: application/json;charset=UTF-8\r\n";
        request_stream << "content-length: " << std::to_string(b64ImgStr.length()) /*"76152"*/ << "\r\n\r\n";
        //request_stream << "Connection: close\r\n\r\n";

        request_stream << "{\"httpMethod\":\"POST\",\"pathWithQueryString\":\"/mxnet-test-dev-hello\",\"body\":\"{\\\"b64Img\\\": \\\""
                       << b64ImgStr << "\\\"}\",\"headers\":{},\"stageVariables\":{},\"withAuthorization\":false}\r\n";
        //request_stream << "Accept: */*\r\n";

        // Start an asynchronous resolve to translate the server and service names
        // into a list of endpoints.
        tcp::resolver::query query(server, "https");
        resolver_.async_resolve(query,
                                boost::bind(&client::handle_resolve, this,
                                            boost::asio::placeholders::error,
                                            boost::asio::placeholders::iterator));
    }

private:

    // http://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
    const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    "abcdefghijklmnopqrstuvwxyz"
                    "0123456789+/";

    std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
        std::string ret;
        int i = 0;
        int j = 0;
        unsigned char char_array_3[3];
        unsigned char char_array_4[4];

        while (in_len--) {
            char_array_3[i++] = *(bytes_to_encode++);
            if (i == 3) {
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;

                for(i = 0; (i <4) ; i++)
                    ret += base64_chars[char_array_4[i]];
                i = 0;
            }
        }

        if (i)
        {
            for(j = i; j < 3; j++)
                char_array_3[j] = '\0';

            char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);

            for (j = 0; (j < i + 1); j++)
                ret += base64_chars[char_array_4[j]];

            while((i++ < 3))
                ret += '=';

        }

        return ret;

    }

    //typedef transform_width< binary_from_base64<remove_whitespace<std::string::const_iterator> >, 8, 6 > it_binary_t;
/*
    std::string b64Encode(const std::string& binaryStr)
    {
        typedef insert_linebreaks<base64_from_binary<transform_width<std::string::const_iterator,6,8> >, 72 > it_base64_t;
        unsigned int writePaddChars = (3-binaryStr.length()%3)%3;
        std::string base64(it_base64_t(binaryStr.begin()),it_base64_t(binaryStr.end()));
        base64.append(writePaddChars,'=');
        return base64;
    }
*/
    void handle_resolve(const boost::system::error_code& err,
                        tcp::resolver::iterator endpoint_iterator)
    {
        if (!err)
        {
            std::cout << "Resolve OK" << "\n";
            socket_.set_verify_mode(boost::asio::ssl::verify_peer);
            socket_.set_verify_callback(
                    boost::bind(&client::verify_certificate, this, _1, _2));

            boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
                                       boost::bind(&client::handle_connect, this,
                                                   boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error resolve: " << err.message() << "\n";
        }
    }

    bool verify_certificate(bool preverified,
                            boost::asio::ssl::verify_context& ctx)
    {
        // The verify callback can be used to check whether the certificate that is
        // being presented is valid for the peer. For example, RFC 2818 describes
        // the steps involved in doing this for HTTPS. Consult the OpenSSL
        // documentation for more details. Note that the callback is called once
        // for each certificate in the certificate chain, starting from the root
        // certificate authority.

        // In this example we will simply print the certificate's subject name.
        char subject_name[256];
        X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
        X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
        std::cout << "Verifying " << subject_name << "\n";

        return preverified;
    }

    void handle_connect(const boost::system::error_code& err)
    {
        if (!err)
        {
            std::cout << "Connect OK " << "\n";
            socket_.async_handshake(boost::asio::ssl::stream_base::client,
                                    boost::bind(&client::handle_handshake, this,
                                                boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Connect failed: " << err.message() << "\n";
        }
    }
// a2fqn2y3y2.execute-api.us-east-1.amazonaws.com /prod/mxnet-test-dev-hello /Users/durst/dev/F16-17/vass/mxnet-serverless/testimg.jpg
    void handle_handshake(const boost::system::error_code& error)
    {
        if (!error)
        {
            std::cout << "Handshake OK " << "\n";
            std::cout << "Request: " << "\n";
            const char* header=boost::asio::buffer_cast<const char*>(request_.data());
            std::cout << header << "\n";

            // The handshake was successful. Send the request.
            boost::asio::async_write(socket_, request_,
                                     boost::bind(&client::handle_write_request, this,
                                                 boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Handshake failed: " << error.message() << "\n";
        }
    }

    void handle_write_request(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Read the response status line. The response_ streambuf will
            // automatically grow to accommodate the entire line. The growth may be
            // limited by passing a maximum size to the streambuf constructor.
            boost::asio::async_read_until(socket_, response_, "\r\n",
                                          boost::bind(&client::handle_read_status_line, this,
                                                      boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error write req: " << err.message() << "\n";
        }
    }

    void handle_read_status_line(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Check that response is OK.
            std::istream response_stream(&response_);
            std::string http_version;
            response_stream >> http_version;
            unsigned int status_code;
            response_stream >> status_code;
            std::string status_message;
            std::getline(response_stream, status_message);
            if (!response_stream || http_version.substr(0, 5) != "HTTP/")
            {
                std::cout << "Invalid response\n";
                return;
            }
            if (status_code != 200)
            {
                std::cout << "Response returned with status code ";
                std::cout << status_code << "\n";
                return;
            }
            std::cout << "Status code: " << status_code << "\n";

            // Read the response headers, which are terminated by a blank line.
            boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
                                          boost::bind(&client::handle_read_headers, this,
                                                      boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error: " << err.message() << "\n";
        }
    }

    void handle_read_headers(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Process the response headers.
            std::istream response_stream(&response_);
            std::string header;
            while (std::getline(response_stream, header) && header != "\r")
                std::cout << header << "\n";
            std::cout << "\n";

            // Write whatever content we already have to output.
            if (response_.size() > 0)
                std::cout << &response_;

            // Start reading remaining data until EOF.
            boost::asio::async_read(socket_, response_,
                                    boost::asio::transfer_at_least(1),
                                    boost::bind(&client::handle_read_content, this,
                                                boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error: " << err << "\n";
        }
    }

    void handle_read_content(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Write all of the data that has been read so far.
            std::cout << &response_;

            // Continue reading remaining data until EOF.
            boost::asio::async_read(socket_, response_,
                                    boost::asio::transfer_at_least(1),
                                    boost::bind(&client::handle_read_content, this,
                                                boost::asio::placeholders::error));
        }
        else if (err != boost::asio::error::eof)
        {
            std::cout << "Error: " << err << "\n";
        }
    }

    tcp::resolver resolver_;
    // https://stackoverflow.com/questions/40036854/creating-a-https-request-using-boost-asio-and-openssl
    // http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/overview/ssl.html
    boost::asio::ssl::context ctx;
    boost::asio::ssl::stream<tcp::socket> socket_;
    boost::asio::streambuf request_;
    boost::asio::streambuf response_;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 4)
        {
            std::cout << "Usage: async_client <server> <path> <fileContainingPostBody>\n";
            std::cout << "Example:\n";
            std::cout << "  async_client www.boost.org /LICENSE_1_0.txt\n";
            return 1;
        }

        boost::asio::io_service io_service;
        std::ifstream b64File(argv[3]);
        std::stringstream b64ImgStream;
        b64ImgStream << b64File.rdbuf();
        std::string binaryImgStr = b64ImgStream.str();
        //client c(io_service, "www.deelay.me", "/1000/hmpg.net");
        client c(io_service, argv[1], argv[2], binaryImgStr);
        io_service.run();
        std::cout << "should print first\n";
    }
    catch (std::exception& e)
    {
        std::cout << "Exception: " << e.what() << "\n";
    }

    return 0;
}
<commit_msg>automatic transaction length calculation<commit_after>//
// async_client.cpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/asio/ssl.hpp>
#include <fstream>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>

using namespace boost::archive::iterators;
using boost::asio::ip::tcp;

class client
{
public:
    client(boost::asio::io_service& io_service,
           const std::string& server, const std::string& path, const std::string& binaryImgStr)
            : resolver_(io_service),
              ctx(io_service, boost::asio::ssl::context::method::tlsv12_client),
              socket_(io_service, ctx)
    {
        SSL_set_tlsext_host_name(socket_.native_handle(),server.c_str());
        ctx.set_default_verify_paths();
        /*ctx.set_options(boost::asio::ssl::context::default_workarounds
                        | boost::asio::ssl::context::no_sslv2
                        | boost::asio::ssl::context::no_sslv3
                        | boost::asio::ssl::context::no_tlsv1
                        | boost::asio::ssl::context::no_tlsv1_1);*/
        //socket_.set_verify_mode(boost::asio::ssl::verify_none);
        //ctx.load_verify_file("ca.pem");
        std::string b64ImgStr = base64_encode(reinterpret_cast<const unsigned char*>(binaryImgStr.c_str()), binaryImgStr.length());
        // Form the request. We specify the "Connection: close" header so that the
        // server will close the socket after transmitting the response. This will
        // allow us to treat all data up until the EOF as the content.
        std::ostream request_stream(&request_);
        request_stream << "POST " << path << " HTTP/1.1\r\n";
        request_stream << "Host: " << server << "\r\n";
        request_stream << "content-type: application/json;charset=UTF-8\r\n";
        std::string bodyStartStr = "{\"httpMethod\":\"POST\",\"pathWithQueryString\":\"/mxnet-test-dev-hello\",\"body\":\"{\\\"b64Img\\\": \\\"";
        std::string bodyEndStr = "\\\"}\",\"headers\":{},\"stageVariables\":{},\"withAuthorization\":false}\r\n";
        request_stream << "content-length: " << std::to_string(bodyStartStr.length() + b64ImgStr.length() + bodyEndStr.length()) << "\r\n\r\n";

        request_stream << bodyStartStr << b64ImgStr << bodyEndStr;
        //request_stream << "Accept: */*\r\n";

        // Start an asynchronous resolve to translate the server and service names
        // into a list of endpoints.
        tcp::resolver::query query(server, "https");
        resolver_.async_resolve(query,
                                boost::bind(&client::handle_resolve, this,
                                            boost::asio::placeholders::error,
                                            boost::asio::placeholders::iterator));
    }

private:

    // http://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
    const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    "abcdefghijklmnopqrstuvwxyz"
                    "0123456789+/";

    std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
        std::string ret;
        int i = 0;
        int j = 0;
        unsigned char char_array_3[3];
        unsigned char char_array_4[4];

        while (in_len--) {
            char_array_3[i++] = *(bytes_to_encode++);
            if (i == 3) {
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;

                for(i = 0; (i <4) ; i++)
                    ret += base64_chars[char_array_4[i]];
                i = 0;
            }
        }

        if (i)
        {
            for(j = i; j < 3; j++)
                char_array_3[j] = '\0';

            char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);

            for (j = 0; (j < i + 1); j++)
                ret += base64_chars[char_array_4[j]];

            while((i++ < 3))
                ret += '=';

        }

        return ret;

    }

    //typedef transform_width< binary_from_base64<remove_whitespace<std::string::const_iterator> >, 8, 6 > it_binary_t;
/*
    std::string b64Encode(const std::string& binaryStr)
    {
        typedef insert_linebreaks<base64_from_binary<transform_width<std::string::const_iterator,6,8> >, 72 > it_base64_t;
        unsigned int writePaddChars = (3-binaryStr.length()%3)%3;
        std::string base64(it_base64_t(binaryStr.begin()),it_base64_t(binaryStr.end()));
        base64.append(writePaddChars,'=');
        return base64;
    }
*/
    void handle_resolve(const boost::system::error_code& err,
                        tcp::resolver::iterator endpoint_iterator)
    {
        if (!err)
        {
            std::cout << "Resolve OK" << "\n";
            socket_.set_verify_mode(boost::asio::ssl::verify_peer);
            socket_.set_verify_callback(
                    boost::bind(&client::verify_certificate, this, _1, _2));

            boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
                                       boost::bind(&client::handle_connect, this,
                                                   boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error resolve: " << err.message() << "\n";
        }
    }

    bool verify_certificate(bool preverified,
                            boost::asio::ssl::verify_context& ctx)
    {
        // The verify callback can be used to check whether the certificate that is
        // being presented is valid for the peer. For example, RFC 2818 describes
        // the steps involved in doing this for HTTPS. Consult the OpenSSL
        // documentation for more details. Note that the callback is called once
        // for each certificate in the certificate chain, starting from the root
        // certificate authority.

        // In this example we will simply print the certificate's subject name.
        char subject_name[256];
        X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
        X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
        std::cout << "Verifying " << subject_name << "\n";

        return preverified;
    }

    void handle_connect(const boost::system::error_code& err)
    {
        if (!err)
        {
            std::cout << "Connect OK " << "\n";
            socket_.async_handshake(boost::asio::ssl::stream_base::client,
                                    boost::bind(&client::handle_handshake, this,
                                                boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Connect failed: " << err.message() << "\n";
        }
    }
// a2fqn2y3y2.execute-api.us-east-1.amazonaws.com /prod/mxnet-test-dev-hello /Users/durst/dev/F16-17/vass/mxnet-serverless/testimg.jpg
    void handle_handshake(const boost::system::error_code& error)
    {
        if (!error)
        {
            std::cout << "Handshake OK " << "\n";
            std::cout << "Request: " << "\n";
            const char* header=boost::asio::buffer_cast<const char*>(request_.data());
            std::cout << header << "\n";

            // The handshake was successful. Send the request.
            boost::asio::async_write(socket_, request_,
                                     boost::bind(&client::handle_write_request, this,
                                                 boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Handshake failed: " << error.message() << "\n";
        }
    }

    void handle_write_request(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Read the response status line. The response_ streambuf will
            // automatically grow to accommodate the entire line. The growth may be
            // limited by passing a maximum size to the streambuf constructor.
            boost::asio::async_read_until(socket_, response_, "\r\n",
                                          boost::bind(&client::handle_read_status_line, this,
                                                      boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error write req: " << err.message() << "\n";
        }
    }

    void handle_read_status_line(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Check that response is OK.
            std::istream response_stream(&response_);
            std::string http_version;
            response_stream >> http_version;
            unsigned int status_code;
            response_stream >> status_code;
            std::string status_message;
            std::getline(response_stream, status_message);
            if (!response_stream || http_version.substr(0, 5) != "HTTP/")
            {
                std::cout << "Invalid response\n";
                return;
            }
            if (status_code != 200)
            {
                std::cout << "Response returned with status code ";
                std::cout << status_code << "\n";
                return;
            }
            std::cout << "Status code: " << status_code << "\n";

            // Read the response headers, which are terminated by a blank line.
            boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
                                          boost::bind(&client::handle_read_headers, this,
                                                      boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error: " << err.message() << "\n";
        }
    }

    void handle_read_headers(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Process the response headers.
            std::istream response_stream(&response_);
            std::string header;
            while (std::getline(response_stream, header) && header != "\r")
                std::cout << header << "\n";
            std::cout << "\n";

            // Write whatever content we already have to output.
            if (response_.size() > 0)
                std::cout << &response_;

            // Start reading remaining data until EOF.
            boost::asio::async_read(socket_, response_,
                                    boost::asio::transfer_at_least(1),
                                    boost::bind(&client::handle_read_content, this,
                                                boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "Error: " << err << "\n";
        }
    }

    void handle_read_content(const boost::system::error_code& err)
    {
        if (!err)
        {
            // Write all of the data that has been read so far.
            std::cout << &response_;

            // Continue reading remaining data until EOF.
            boost::asio::async_read(socket_, response_,
                                    boost::asio::transfer_at_least(1),
                                    boost::bind(&client::handle_read_content, this,
                                                boost::asio::placeholders::error));
        }
        else if (err != boost::asio::error::eof)
        {
            std::cout << "Error: " << err << "\n";
        }
    }

    tcp::resolver resolver_;
    // https://stackoverflow.com/questions/40036854/creating-a-https-request-using-boost-asio-and-openssl
    // http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/overview/ssl.html
    boost::asio::ssl::context ctx;
    boost::asio::ssl::stream<tcp::socket> socket_;
    boost::asio::streambuf request_;
    boost::asio::streambuf response_;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 4)
        {
            std::cout << "Usage: async_client <server> <path> <fileContainingPostBody>\n";
            std::cout << "Example:\n";
            std::cout << "  async_client www.boost.org /LICENSE_1_0.txt\n";
            return 1;
        }

        boost::asio::io_service io_service;
        std::ifstream b64File(argv[3]);
        std::stringstream b64ImgStream;
        b64ImgStream << b64File.rdbuf();
        std::string binaryImgStr = b64ImgStream.str();
        //client c(io_service, "www.deelay.me", "/1000/hmpg.net");
        client c(io_service, argv[1], argv[2], binaryImgStr);
        io_service.run();
        std::cout << "should print first\n";
    }
    catch (std::exception& e)
    {
        std::cout << "Exception: " << e.what() << "\n";
    }

    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2014 Open Source Robotics Foundation, 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.

#ifndef RCLCPP__EXECUTOR_HPP_
#define RCLCPP__EXECUTOR_HPP_

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <list>
#include <memory>
#include <vector>

#include "rclcpp/any_executable.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"

namespace rclcpp
{
namespace executor
{

/// Return codes to be used with spin_until_future_complete.
/**
 * SUCCESS: The future is complete and can be accessed with "get" without blocking.
 * INTERRUPTED: The future is not complete, spinning was interrupted by Ctrl-C or another error.
 * TIMEOUT: Spinning timed out.
 */
enum FutureReturnCode {SUCCESS, INTERRUPTED, TIMEOUT};

/// Coordinate the order and timing of available communication tasks.
/**
 * Executor provides spin functions (including spin_node_once and spin_some).
 * It coordinates the nodes and callback groups by looking for available work and completing it,
 * based on the threading or concurrency scheme provided by the subclass implementation.
 * An example of available work is executing a subscription callback, or a timer callback.
 * The executor structure allows for a decoupling of the communication graph and the execution
 * model.
 * See SingleThreadedExecutor and MultiThreadedExecutor for examples of execution paradigms.
 */
class Executor
{
public:
  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Executor);

  /// Default constructor.
  // \param[in] ms The memory strategy to be used with this executor.
  RCLCPP_PUBLIC
  explicit Executor(
    memory_strategy::MemoryStrategy::SharedPtr ms = memory_strategies::create_default_strategy());

  /// Default destructor.
  RCLCPP_PUBLIC
  virtual ~Executor();

  /// Do work periodically as it becomes available to us. Blocking call, may block indefinitely.
  // It is up to the implementation of Executor to implement spin.
  virtual void
  spin() = 0;

  /// Add a node to the executor.
  /**
   * An executor can have zero or more nodes which provide work during `spin` functions.
   * \param[in] node_ptr Shared pointer to the node to be added.
   * \param[in] notify True to trigger the interrupt guard condition during this function. If
   * the executor is blocked at the rmw layer while waiting for work and it is notified that a new
   * node was added, it will wake up.
   */
  RCLCPP_PUBLIC
  virtual void
  add_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify = true);

  /// Remove a node from the executor.
  /**
   * \param[in] node_ptr Shared pointer to the node to remove.
   * \param[in] notify True to trigger the interrupt guard condition and wake up the executor.
   * This is useful if the last node was removed from the executor while the executor was blocked
   * waiting for work in another thread, because otherwise the executor would never be notified.
   */
  RCLCPP_PUBLIC
  virtual void
  remove_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify = true);

  /// Add a node to executor, execute the next available unit of work, and remove the node.
  /**
   * \param[in] node Shared pointer to the node to add.
   * \param[in] timeout How long to wait for work to become available. Negative values cause
   * spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
   * function to be non-blocking.
   */
  template<typename T = std::milli>
  void
  spin_node_once(rclcpp::node::Node::SharedPtr node,
    std::chrono::duration<int64_t, T> timeout = std::chrono::duration<int64_t, T>(-1))
  {
    return spin_node_once_nanoseconds(
      node,
      std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
    );
  }

  /// Add a node, complete all immediately available work, and remove the node.
  /**
   * \param[in] node Shared pointer to the node to add.
   */
  RCLCPP_PUBLIC
  void
  spin_node_some(rclcpp::node::Node::SharedPtr node);

  /// Complete all available queued work without blocking.
  /**
   * This function can be overridden. The default implementation is suitable for a
   * single-threaded model of execution.
   * Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
   * to block (which may have unintended consequences).
   */
  RCLCPP_PUBLIC
  virtual void
  spin_some();

  RCLCPP_PUBLIC
  virtual void
  spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));

  /// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
  /**
   * \param[in] executor The executor which will spin the node.
   * \param[in] node_ptr The node to spin.
   * \param[in] future The future to wait on. If SUCCESS, the future is safe to access after this function
   * \param[in] timeout Optional timeout parameter, which gets passed to Executor::spin_node_once.
     -1 is block forever, 0 is non-blocking.
     If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return code.
   * \return The return code, one of SUCCESS, INTERRUPTED, or TIMEOUT.
   */
  template<typename ResponseT, typename TimeT = std::milli>
  FutureReturnCode
  spin_until_future_complete(
    std::shared_future<ResponseT> & future,
    std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
  {
    // TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
    // inside a callback executed by an executor.

    // Check the future before entering the while loop.
    // If the future is already complete, don't try to spin.
    std::future_status status = future.wait_for(std::chrono::seconds(0));

    auto start_time = std::chrono::system_clock::now();

    while (status != std::future_status::ready && rclcpp::utilities::ok()) {
      spin_once(timeout);
      if (timeout.count() >= 0) {
        if (start_time + timeout < std::chrono::system_clock::now()) {
          return TIMEOUT;
        }
      }
      status = future.wait_for(std::chrono::seconds(0));
    }

    // If the future completed, and we weren't interrupted by ctrl-C, return the response
    if (status == std::future_status::ready) {
      return FutureReturnCode::SUCCESS;
    }
    return FutureReturnCode::INTERRUPTED;
  }

  /// Cancels any running spin* function, causing it to return.
  /* This function can be called asynchonously from any thread. */
  RCLCPP_PUBLIC
  void
  cancel();

  /// Support dynamic switching of the memory strategy.
  /**
   * Switching the memory strategy while the executor is spinning in another threading could have
   * unintended consequences.
   * \param[in] memory_strategy Shared pointer to the memory strategy to set.
   */
  RCLCPP_PUBLIC
  void
  set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);

protected:
  RCLCPP_PUBLIC
  void
  spin_node_once_nanoseconds(rclcpp::node::Node::SharedPtr node, std::chrono::nanoseconds timeout);

  /// Find the next available executable and do the work associated with it.
  /** \param[in] any_exec Union structure that can hold any executable type (timer, subscription,
   * service, client).
   */
  RCLCPP_PUBLIC
  void
  execute_any_executable(AnyExecutable::SharedPtr any_exec);

  RCLCPP_PUBLIC
  static void
  execute_subscription(
    rclcpp::subscription::SubscriptionBase::SharedPtr subscription);

  RCLCPP_PUBLIC
  static void
  execute_intra_process_subscription(
    rclcpp::subscription::SubscriptionBase::SharedPtr subscription);

  RCLCPP_PUBLIC
  static void
  execute_timer(rclcpp::timer::TimerBase::SharedPtr timer);

  RCLCPP_PUBLIC
  static void
  execute_service(rclcpp::service::ServiceBase::SharedPtr service);

  RCLCPP_PUBLIC
  static void
  execute_client(rclcpp::client::ClientBase::SharedPtr client);

  RCLCPP_PUBLIC
  void
  wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));

  RCLCPP_PUBLIC
  rclcpp::node::Node::SharedPtr
  get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group);

  RCLCPP_PUBLIC
  rclcpp::callback_group::CallbackGroup::SharedPtr
  get_group_by_timer(rclcpp::timer::TimerBase::SharedPtr timer);

  RCLCPP_PUBLIC
  void
  get_next_timer(AnyExecutable::SharedPtr any_exec);

  RCLCPP_PUBLIC
  std::chrono::nanoseconds
  get_earliest_timer();

  RCLCPP_PUBLIC
  AnyExecutable::SharedPtr
  get_next_ready_executable();

  RCLCPP_PUBLIC
  AnyExecutable::SharedPtr
  get_next_executable(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));

  /// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
  std::atomic_bool spinning;

  /// Guard condition for signaling the rmw layer to wake up for special events.
  rmw_guard_condition_t * interrupt_guard_condition_;

  /// The memory strategy: an interface for handling user-defined memory allocation strategies.
  memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;

private:
  RCLCPP_DISABLE_COPY(Executor);

  std::vector<std::weak_ptr<rclcpp::node::Node>> weak_nodes_;
  std::array<void *, 2> guard_cond_handles_;
};

}  // namespace executor
}  // namespace rclcpp

#endif  // RCLCPP__EXECUTOR_HPP_
<commit_msg>Cancel instead of cancels<commit_after>// Copyright 2014 Open Source Robotics Foundation, 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.

#ifndef RCLCPP__EXECUTOR_HPP_
#define RCLCPP__EXECUTOR_HPP_

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <list>
#include <memory>
#include <vector>

#include "rclcpp/any_executable.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"

namespace rclcpp
{
namespace executor
{

/// Return codes to be used with spin_until_future_complete.
/**
 * SUCCESS: The future is complete and can be accessed with "get" without blocking.
 * INTERRUPTED: The future is not complete, spinning was interrupted by Ctrl-C or another error.
 * TIMEOUT: Spinning timed out.
 */
enum FutureReturnCode {SUCCESS, INTERRUPTED, TIMEOUT};

/// Coordinate the order and timing of available communication tasks.
/**
 * Executor provides spin functions (including spin_node_once and spin_some).
 * It coordinates the nodes and callback groups by looking for available work and completing it,
 * based on the threading or concurrency scheme provided by the subclass implementation.
 * An example of available work is executing a subscription callback, or a timer callback.
 * The executor structure allows for a decoupling of the communication graph and the execution
 * model.
 * See SingleThreadedExecutor and MultiThreadedExecutor for examples of execution paradigms.
 */
class Executor
{
public:
  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Executor);

  /// Default constructor.
  // \param[in] ms The memory strategy to be used with this executor.
  RCLCPP_PUBLIC
  explicit Executor(
    memory_strategy::MemoryStrategy::SharedPtr ms = memory_strategies::create_default_strategy());

  /// Default destructor.
  RCLCPP_PUBLIC
  virtual ~Executor();

  /// Do work periodically as it becomes available to us. Blocking call, may block indefinitely.
  // It is up to the implementation of Executor to implement spin.
  virtual void
  spin() = 0;

  /// Add a node to the executor.
  /**
   * An executor can have zero or more nodes which provide work during `spin` functions.
   * \param[in] node_ptr Shared pointer to the node to be added.
   * \param[in] notify True to trigger the interrupt guard condition during this function. If
   * the executor is blocked at the rmw layer while waiting for work and it is notified that a new
   * node was added, it will wake up.
   */
  RCLCPP_PUBLIC
  virtual void
  add_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify = true);

  /// Remove a node from the executor.
  /**
   * \param[in] node_ptr Shared pointer to the node to remove.
   * \param[in] notify True to trigger the interrupt guard condition and wake up the executor.
   * This is useful if the last node was removed from the executor while the executor was blocked
   * waiting for work in another thread, because otherwise the executor would never be notified.
   */
  RCLCPP_PUBLIC
  virtual void
  remove_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify = true);

  /// Add a node to executor, execute the next available unit of work, and remove the node.
  /**
   * \param[in] node Shared pointer to the node to add.
   * \param[in] timeout How long to wait for work to become available. Negative values cause
   * spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
   * function to be non-blocking.
   */
  template<typename T = std::milli>
  void
  spin_node_once(rclcpp::node::Node::SharedPtr node,
    std::chrono::duration<int64_t, T> timeout = std::chrono::duration<int64_t, T>(-1))
  {
    return spin_node_once_nanoseconds(
      node,
      std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
    );
  }

  /// Add a node, complete all immediately available work, and remove the node.
  /**
   * \param[in] node Shared pointer to the node to add.
   */
  RCLCPP_PUBLIC
  void
  spin_node_some(rclcpp::node::Node::SharedPtr node);

  /// Complete all available queued work without blocking.
  /**
   * This function can be overridden. The default implementation is suitable for a
   * single-threaded model of execution.
   * Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
   * to block (which may have unintended consequences).
   */
  RCLCPP_PUBLIC
  virtual void
  spin_some();

  RCLCPP_PUBLIC
  virtual void
  spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));

  /// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
  /**
   * \param[in] executor The executor which will spin the node.
   * \param[in] node_ptr The node to spin.
   * \param[in] future The future to wait on. If SUCCESS, the future is safe to access after this function
   * \param[in] timeout Optional timeout parameter, which gets passed to Executor::spin_node_once.
     -1 is block forever, 0 is non-blocking.
     If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return code.
   * \return The return code, one of SUCCESS, INTERRUPTED, or TIMEOUT.
   */
  template<typename ResponseT, typename TimeT = std::milli>
  FutureReturnCode
  spin_until_future_complete(
    std::shared_future<ResponseT> & future,
    std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
  {
    // TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
    // inside a callback executed by an executor.

    // Check the future before entering the while loop.
    // If the future is already complete, don't try to spin.
    std::future_status status = future.wait_for(std::chrono::seconds(0));

    auto start_time = std::chrono::system_clock::now();

    while (status != std::future_status::ready && rclcpp::utilities::ok()) {
      spin_once(timeout);
      if (timeout.count() >= 0) {
        if (start_time + timeout < std::chrono::system_clock::now()) {
          return TIMEOUT;
        }
      }
      status = future.wait_for(std::chrono::seconds(0));
    }

    // If the future completed, and we weren't interrupted by ctrl-C, return the response
    if (status == std::future_status::ready) {
      return FutureReturnCode::SUCCESS;
    }
    return FutureReturnCode::INTERRUPTED;
  }

  /// Cancel any running spin* function, causing it to return.
  /* This function can be called asynchonously from any thread. */
  RCLCPP_PUBLIC
  void
  cancel();

  /// Support dynamic switching of the memory strategy.
  /**
   * Switching the memory strategy while the executor is spinning in another threading could have
   * unintended consequences.
   * \param[in] memory_strategy Shared pointer to the memory strategy to set.
   */
  RCLCPP_PUBLIC
  void
  set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);

protected:
  RCLCPP_PUBLIC
  void
  spin_node_once_nanoseconds(rclcpp::node::Node::SharedPtr node, std::chrono::nanoseconds timeout);

  /// Find the next available executable and do the work associated with it.
  /** \param[in] any_exec Union structure that can hold any executable type (timer, subscription,
   * service, client).
   */
  RCLCPP_PUBLIC
  void
  execute_any_executable(AnyExecutable::SharedPtr any_exec);

  RCLCPP_PUBLIC
  static void
  execute_subscription(
    rclcpp::subscription::SubscriptionBase::SharedPtr subscription);

  RCLCPP_PUBLIC
  static void
  execute_intra_process_subscription(
    rclcpp::subscription::SubscriptionBase::SharedPtr subscription);

  RCLCPP_PUBLIC
  static void
  execute_timer(rclcpp::timer::TimerBase::SharedPtr timer);

  RCLCPP_PUBLIC
  static void
  execute_service(rclcpp::service::ServiceBase::SharedPtr service);

  RCLCPP_PUBLIC
  static void
  execute_client(rclcpp::client::ClientBase::SharedPtr client);

  RCLCPP_PUBLIC
  void
  wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));

  RCLCPP_PUBLIC
  rclcpp::node::Node::SharedPtr
  get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group);

  RCLCPP_PUBLIC
  rclcpp::callback_group::CallbackGroup::SharedPtr
  get_group_by_timer(rclcpp::timer::TimerBase::SharedPtr timer);

  RCLCPP_PUBLIC
  void
  get_next_timer(AnyExecutable::SharedPtr any_exec);

  RCLCPP_PUBLIC
  std::chrono::nanoseconds
  get_earliest_timer();

  RCLCPP_PUBLIC
  AnyExecutable::SharedPtr
  get_next_ready_executable();

  RCLCPP_PUBLIC
  AnyExecutable::SharedPtr
  get_next_executable(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));

  /// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
  std::atomic_bool spinning;

  /// Guard condition for signaling the rmw layer to wake up for special events.
  rmw_guard_condition_t * interrupt_guard_condition_;

  /// The memory strategy: an interface for handling user-defined memory allocation strategies.
  memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;

private:
  RCLCPP_DISABLE_COPY(Executor);

  std::vector<std::weak_ptr<rclcpp::node::Node>> weak_nodes_;
  std::array<void *, 2> guard_cond_handles_;
};

}  // namespace executor
}  // namespace rclcpp

#endif  // RCLCPP__EXECUTOR_HPP_
<|endoftext|>


<commit_before>/*  -*- mode: C++; c-file-style: "gnu" -*-
    aboutdata.cpp

    This file is part of KMail, the KDE mail client.
    Copyright (c) 2003 Marc Mutz <mutz@kde.org>

    KMail is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License, version 2, as
    published by the Free Software Foundation.

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

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

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "aboutdata.h"

#include "kmversion.h"

#include <klocale.h>

namespace KMail {

  struct about_data {
    const char * name;
    const char * desc;
    const char * email;
    const char * web;
  };

  // This file should not be changed by anybody other than the maintainer
  // If you change the maintainer here, change it in the MAINTAINERS file in the
  // top level kdepim folder as well.

  static const about_data authors[] = {
    { "Thomas McGuire", I18N_NOOP("Maintainer"),
      "mcguire@kde.org", 0 },
    { "Stefan Taferner", I18N_NOOP("Original author"),
      "taferner@kde.org", 0 },
    { "Michael H\303\244ckel", I18N_NOOP("Former maintainer"),
      "haeckel@kde.org", 0 },
    { "Ingo Kl\303\266cker", I18N_NOOP("Former maintainer"),
      "kloecker@kde.org", 0 },
    { "Don Sanders", I18N_NOOP("Former co-maintainer"),
      "sanders@kde.org", 0 },

    { "Till Adam", I18N_NOOP("Core developer"),
      "adam@kde.org", 0 },
    { "Volker Krause", I18N_NOOP("Core developer"),
      "vkrause@kde.org", 0 },
    { "Carsten Burghardt", I18N_NOOP("Former core developer"),
      "burghardt@kde.org", 0 },
    { "Marc Mutz", I18N_NOOP("Former core developer"),
      "mutz@kde.org", 0 },
    { "Zack Rusin", I18N_NOOP("Former core developer"),
      "zack@kde.org", 0 },
    { "Daniel Naber", I18N_NOOP("Documentation"),
      "daniel.naber@t-online.de", 0 },

    { "Toyohiro Asukai", 0,
      "toyohiro@ksmplus.com", 0 },
    { "Waldo Bastian", 0,
      "bastian@kde.org", 0 },
    { "Ryan Breen", I18N_NOOP("system tray notification"),
      "ryan@ryanbreen.com", 0 },
    { "Steven Brown", 0,
      "swbrown@ucsd.edu", 0 },
    { "Matthias Kalle Dalheimer", 0,
      "kalle@kde.org", 0 },
    { "Matt Douhan", 0,
      "matt@fruitsalad.org", 0 },
    { "Cristi Dumitrescu", 0,
      "cristid@chip.ro", 0 },
    { "David Faure", 0,
      "faure@kde.org", 0 },
    { "Philippe Fremy", 0,
      "pfremy@chez.com", 0 },
    { "Kurt Granroth", 0,
      "granroth@kde.org", 0 },
    { "Andreas Gungl", I18N_NOOP("PGP 6 support and further enhancements of the encryption support"),
      "a.gungl@gmx.de", 0 },
    { "Steffen Hansen", 0,
      "hansen@kde.org", 0 },
    { "Igor Janssen", 0,
      "rm@linux.ru.net", 0 },
    { "Matt Johnston", 0,
      "matt@caifex.org", 0 },
    { "Christer Kaivo-oja", 0,
      "whizkid@telia.com", 0 },
    { "Lars Knoll", I18N_NOOP("Original encryption support
"
                              "PGP 2 and PGP 5 support"),
      "knoll@kde.org", 0 },
    { "J. Nick Koston", I18N_NOOP("GnuPG support"),
      "bdraco@darkorb.net", 0 },
    { "Stephan Kulow", 0,
      "coolo@kde.org", 0 },
    { "Guillaume Laurent", 0,
      "glaurent@telegraph-road.org", 0 },
    { "Sam Magnuson", 0,
      "sam@trolltech.com", 0 },
    { "Laurent Montel", 0,
      "lmontel@mandrakesoft.com", 0 },
    { "Matt Newell", 0,
      "newellm@proaxis.com", 0 },
    { "Denis Perchine", 0,
      "dyp@perchine.com", 0 },
    { "Samuel Penn", 0,
      "sam@bifrost.demon.co.uk", 0 },
    { "Carsten Pfeiffer", 0,
      "pfeiffer@kde.org", 0 },
    { "Sven Radej", 0,
      "radej@kde.org", 0 },
    { "Mark Roberts", 0,
      "mark@taurine.demon.co.uk", 0 },
    { "Wolfgang Rohdewald", 0,
      "wolfgang@rohdewald.de", 0 },
    { "Espen Sand", 0,
      "espen@kde.org", 0 },
    { "Aaron J. Seigo", 0,
      "aseigo@olympusproject.org", 0 },
    { "George Staikos", 0,
      "staikos@kde.org", 0 },
    { "Szymon Stefanek", I18N_NOOP( "New message list and new folder tree" ),
      "pragma@kvirc.net", 0 },
    { "Jason Stephenson", 0,
      "panda@mis.net", 0 },
    { "Jacek Stolarczyk", 0,
      "jacek@mer.chemia.polsl.gliwice.pl", 0 },
    { "Roberto S. Teixeira", 0,
      "maragato@kde.org", 0 },
    { "Bo Thorsen", 0,
      "bo@sonofthor.dk", 0 },
    { "Ronen Tzur", 0,
      "rtzur@shani.net", 0 },
    { "Mario Weilguni", 0,
      "mweilguni@sime.com", 0 },
    { "Wynn Wilkes", 0,
      "wynnw@calderasystems.com", 0 },
    { "Robert D. Williams", 0,
      "rwilliams@kde.org", 0 },
    { "Markus W\303\274bben", 0,
      "markus.wuebben@kde.org", 0 },
    { "Karl-Heinz Zimmer", 0,
      "khz@kde.org", 0 }
  };

  static const about_data credits[] = {
    { "Sam Abed", 0, 0, 0 }, // KConfigXT porting, smileys->emoticons replacement
    { "Joern Ahrens", 0, 0, 0 }, // implement wish 77182 (Add some separators to "Mark Message as" popup menu)
    { "Tom Albers", 0, 0, 0 }, // small fixes, bugzilla maintenance
    { "Albert Cervera Areny", 0, 0, 0 }, // implemented wish 88309 (optional compression of attachments)
    { "Patrick Audley", 0, 0, 0 }, // add optional graphical spam status to fancy headers
    { "Benjamin Azan", 0, 0, 0 }, // implemented todo status handling
    { "Albert Astals Cid", 0, 0, 0 }, // fix for bug:95441 (folder tree context menu doesn't show shortcuts assigned to the actions)
    { "Cornelius Schumacher", 0, "schumacher@kde.org", 0 }, // implemented the new recipients editor and picker
    { "Frederick Emmott", I18N_NOOP("Anti-virus support"),
      "fred87@users.sf.net", 0 },
    { "Sandro Giessl", 0, 0, 0 }, // frame width fixes for widget styles
    { "Severin Greimel", 0, 0, 0 }, // several patches
    { "Shaheed Haque", 0, 0, 0 }, // fix for bug:69744 (Resource folders: "Journals" should be "Journal")
    { "Ingo Heeskens", 0, 0, 0 }, // implemented wish 34857 (per folder option for loading external references)
    { "Kurt Hindenburg", 0, 0, 0 }, // implemented wish 89003 (delete whole thread)
    { "Heiko Hund", I18N_NOOP("POP filters"),
      "heiko@ist.eigentlich.net", 0 },
    { "Torsten Kasch", 0, 0, 0 }, // crash fix for Solaris (cf. bug:68801)
    { "Jason 'vanRijn' Kasper", 0, 0, 0 }, // implemented wish 79938 (configurable font for new/unread/important messages)
    { "Martijn Klingens", 0, 0, 0 }, // fix keyboard navigation in the Status combo of the quick search
    { "Christoph Kl\303\274nter", 0, 0, 0 }, // fix for bug:88216 (drag&drop from KAddressBook to the To: field)
    { "Martin Koller", 0, 0, 0 }, // optional columns in the message list
    { "Tobias K\303\266nig", 0, 0, 0 }, // edit recent addresses, store email<->OpenPGP key association in address book
    { "Francois Kritzinger", 0, 0, 0 }, // fix bug in configuration dialog
    { "Danny Kukawka", 0, 0, 0 }, // DCOP enhancements for better message importing
    { "Roger Larsson", 0, 0, 0 }, // add name of checked account to status bar message
    { "Jeffrey McGee", 0, 0, 0 }, // fix for bug:64251
    { "Dirk M\303\274ller", 0, 0, 0 }, // KUrl() fixes and qt_cast optimizations
    { "OpenUsability", I18N_NOOP("Usability tests and improvements"), 0, "http://www.openusability.org" },
    { "Mario Teijeiro Otero", 0, 0, 0 }, // various vendor annotations fixes
    { "Simon Perreault", 0, 0, 0 }, // make the composer remember its "Use Fixed Font" setting (bug 49481)
    { "Bernhard Reiter", I18N_NOOP("\xC3\x84gypten and Kroupware project management"),
      "bernhard@intevation.de", 0 },
    { "Edwin Schepers", 0, "yez@familieschepers.nl", 0 }, // composition of HTML messages
    { "Jakob Schr\303\266ter", 0, 0, 0 }, // implemented wish 28319 (X-Face support)
    { "Jan Simonson", I18N_NOOP("beta testing of PGP 6 support"),
      "jan@simonson.pp.se", 0 },
    { "Paul Sprakes", 0, 0, 0 }, // fix for bug:63619 (filter button in toolbar doesn't work), context menu clean up
    { "Will Stephenson", 0, 0, 0 }, // added IM status indicator
    { "Hasso Tepper", 0, 0, 0 }, // improve layout of recipients editor
    { "Patrick S. Vogt", I18N_NOOP("timestamp for 'Transmission completed' status messages"),
      "patrick.vogt@unibas.ch", 0 },
    { "Jan-Oliver Wagner", I18N_NOOP("\xC3\x84gypten and Kroupware project management"),
      "jan@intevation.de", 0 },
    { "Wolfgang Westphal", I18N_NOOP("multiple encryption keys per address"),
      "wolfgang.westphal@gmx.de", 0 },
    { "Thorsten Zachmann", I18N_NOOP("POP filters"),
      "t.zachmann@zagge.de", 0 },
    { "Thomas Zander", 0, 0, 0 }
  };

  AboutData::AboutData()
    : KAboutData( "kmail", 0, ki18n("KMail"),KMAIL_VERSION,
                  ki18n("KDE Email Client"), License_GPL,
                  ki18n("(c) 1997-2009, The KMail developers"), KLocalizedString(),
                  "http://kontact.kde.org/kmail/" )
  {
    using KMail::authors;
    using KMail::credits;
    for ( unsigned int i = 0 ; i < sizeof authors / sizeof *authors ; ++i )
      addAuthor( ki18n(authors[i].name), ki18n(authors[i].desc), authors[i].email, authors[i].web );
    for ( unsigned int i = 0 ; i < sizeof credits / sizeof *credits ; ++i )
      addCredit( ki18n(credits[i].name), ki18n(credits[i].desc), credits[i].email, credits[i].web );
  }

  AboutData::~AboutData() {

  }

} // namespace KMail
<commit_msg>Update email<commit_after>/*  -*- mode: C++; c-file-style: "gnu" -*-
    aboutdata.cpp

    This file is part of KMail, the KDE mail client.
    Copyright (c) 2003 Marc Mutz <mutz@kde.org>

    KMail is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License, version 2, as
    published by the Free Software Foundation.

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

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

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "aboutdata.h"

#include "kmversion.h"

#include <klocale.h>

namespace KMail {

  struct about_data {
    const char * name;
    const char * desc;
    const char * email;
    const char * web;
  };

  // This file should not be changed by anybody other than the maintainer
  // If you change the maintainer here, change it in the MAINTAINERS file in the
  // top level kdepim folder as well.

  static const about_data authors[] = {
    { "Thomas McGuire", I18N_NOOP("Maintainer"),
      "mcguire@kde.org", 0 },
    { "Stefan Taferner", I18N_NOOP("Original author"),
      "taferner@kde.org", 0 },
    { "Michael H\303\244ckel", I18N_NOOP("Former maintainer"),
      "haeckel@kde.org", 0 },
    { "Ingo Kl\303\266cker", I18N_NOOP("Former maintainer"),
      "kloecker@kde.org", 0 },
    { "Don Sanders", I18N_NOOP("Former co-maintainer"),
      "sanders@kde.org", 0 },

    { "Till Adam", I18N_NOOP("Core developer"),
      "adam@kde.org", 0 },
    { "Volker Krause", I18N_NOOP("Core developer"),
      "vkrause@kde.org", 0 },
    { "Carsten Burghardt", I18N_NOOP("Former core developer"),
      "burghardt@kde.org", 0 },
    { "Marc Mutz", I18N_NOOP("Former core developer"),
      "mutz@kde.org", 0 },
    { "Zack Rusin", I18N_NOOP("Former core developer"),
      "zack@kde.org", 0 },
    { "Daniel Naber", I18N_NOOP("Documentation"),
      "daniel.naber@t-online.de", 0 },

    { "Toyohiro Asukai", 0,
      "toyohiro@ksmplus.com", 0 },
    { "Waldo Bastian", 0,
      "bastian@kde.org", 0 },
    { "Ryan Breen", I18N_NOOP("system tray notification"),
      "ryan@ryanbreen.com", 0 },
    { "Steven Brown", 0,
      "swbrown@ucsd.edu", 0 },
    { "Matthias Kalle Dalheimer", 0,
      "kalle@kde.org", 0 },
    { "Matt Douhan", 0,
      "matt@fruitsalad.org", 0 },
    { "Cristi Dumitrescu", 0,
      "cristid@chip.ro", 0 },
    { "David Faure", 0,
      "faure@kde.org", 0 },
    { "Philippe Fremy", 0,
      "pfremy@chez.com", 0 },
    { "Kurt Granroth", 0,
      "granroth@kde.org", 0 },
    { "Andreas Gungl", I18N_NOOP("PGP 6 support and further enhancements of the encryption support"),
      "a.gungl@gmx.de", 0 },
    { "Steffen Hansen", 0,
      "hansen@kde.org", 0 },
    { "Igor Janssen", 0,
      "rm@linux.ru.net", 0 },
    { "Matt Johnston", 0,
      "matt@caifex.org", 0 },
    { "Christer Kaivo-oja", 0,
      "whizkid@telia.com", 0 },
    { "Lars Knoll", I18N_NOOP("Original encryption support
"
                              "PGP 2 and PGP 5 support"),
      "knoll@kde.org", 0 },
    { "J. Nick Koston", I18N_NOOP("GnuPG support"),
      "bdraco@darkorb.net", 0 },
    { "Stephan Kulow", 0,
      "coolo@kde.org", 0 },
    { "Guillaume Laurent", 0,
      "glaurent@telegraph-road.org", 0 },
    { "Sam Magnuson", 0,
      "sam@trolltech.com", 0 },
    { "Laurent Montel", 0,
      "montel@kde.org", 0 },
    { "Matt Newell", 0,
      "newellm@proaxis.com", 0 },
    { "Denis Perchine", 0,
      "dyp@perchine.com", 0 },
    { "Samuel Penn", 0,
      "sam@bifrost.demon.co.uk", 0 },
    { "Carsten Pfeiffer", 0,
      "pfeiffer@kde.org", 0 },
    { "Sven Radej", 0,
      "radej@kde.org", 0 },
    { "Mark Roberts", 0,
      "mark@taurine.demon.co.uk", 0 },
    { "Wolfgang Rohdewald", 0,
      "wolfgang@rohdewald.de", 0 },
    { "Espen Sand", 0,
      "espen@kde.org", 0 },
    { "Aaron J. Seigo", 0,
      "aseigo@olympusproject.org", 0 },
    { "George Staikos", 0,
      "staikos@kde.org", 0 },
    { "Szymon Stefanek", I18N_NOOP( "New message list and new folder tree" ),
      "pragma@kvirc.net", 0 },
    { "Jason Stephenson", 0,
      "panda@mis.net", 0 },
    { "Jacek Stolarczyk", 0,
      "jacek@mer.chemia.polsl.gliwice.pl", 0 },
    { "Roberto S. Teixeira", 0,
      "maragato@kde.org", 0 },
    { "Bo Thorsen", 0,
      "bo@sonofthor.dk", 0 },
    { "Ronen Tzur", 0,
      "rtzur@shani.net", 0 },
    { "Mario Weilguni", 0,
      "mweilguni@sime.com", 0 },
    { "Wynn Wilkes", 0,
      "wynnw@calderasystems.com", 0 },
    { "Robert D. Williams", 0,
      "rwilliams@kde.org", 0 },
    { "Markus W\303\274bben", 0,
      "markus.wuebben@kde.org", 0 },
    { "Karl-Heinz Zimmer", 0,
      "khz@kde.org", 0 }
  };

  static const about_data credits[] = {
    { "Sam Abed", 0, 0, 0 }, // KConfigXT porting, smileys->emoticons replacement
    { "Joern Ahrens", 0, 0, 0 }, // implement wish 77182 (Add some separators to "Mark Message as" popup menu)
    { "Tom Albers", 0, 0, 0 }, // small fixes, bugzilla maintenance
    { "Albert Cervera Areny", 0, 0, 0 }, // implemented wish 88309 (optional compression of attachments)
    { "Patrick Audley", 0, 0, 0 }, // add optional graphical spam status to fancy headers
    { "Benjamin Azan", 0, 0, 0 }, // implemented todo status handling
    { "Albert Astals Cid", 0, 0, 0 }, // fix for bug:95441 (folder tree context menu doesn't show shortcuts assigned to the actions)
    { "Cornelius Schumacher", 0, "schumacher@kde.org", 0 }, // implemented the new recipients editor and picker
    { "Frederick Emmott", I18N_NOOP("Anti-virus support"),
      "fred87@users.sf.net", 0 },
    { "Sandro Giessl", 0, 0, 0 }, // frame width fixes for widget styles
    { "Severin Greimel", 0, 0, 0 }, // several patches
    { "Shaheed Haque", 0, 0, 0 }, // fix for bug:69744 (Resource folders: "Journals" should be "Journal")
    { "Ingo Heeskens", 0, 0, 0 }, // implemented wish 34857 (per folder option for loading external references)
    { "Kurt Hindenburg", 0, 0, 0 }, // implemented wish 89003 (delete whole thread)
    { "Heiko Hund", I18N_NOOP("POP filters"),
      "heiko@ist.eigentlich.net", 0 },
    { "Torsten Kasch", 0, 0, 0 }, // crash fix for Solaris (cf. bug:68801)
    { "Jason 'vanRijn' Kasper", 0, 0, 0 }, // implemented wish 79938 (configurable font for new/unread/important messages)
    { "Martijn Klingens", 0, 0, 0 }, // fix keyboard navigation in the Status combo of the quick search
    { "Christoph Kl\303\274nter", 0, 0, 0 }, // fix for bug:88216 (drag&drop from KAddressBook to the To: field)
    { "Martin Koller", 0, 0, 0 }, // optional columns in the message list
    { "Tobias K\303\266nig", 0, 0, 0 }, // edit recent addresses, store email<->OpenPGP key association in address book
    { "Francois Kritzinger", 0, 0, 0 }, // fix bug in configuration dialog
    { "Danny Kukawka", 0, 0, 0 }, // DCOP enhancements for better message importing
    { "Roger Larsson", 0, 0, 0 }, // add name of checked account to status bar message
    { "Jeffrey McGee", 0, 0, 0 }, // fix for bug:64251
    { "Dirk M\303\274ller", 0, 0, 0 }, // KUrl() fixes and qt_cast optimizations
    { "OpenUsability", I18N_NOOP("Usability tests and improvements"), 0, "http://www.openusability.org" },
    { "Mario Teijeiro Otero", 0, 0, 0 }, // various vendor annotations fixes
    { "Simon Perreault", 0, 0, 0 }, // make the composer remember its "Use Fixed Font" setting (bug 49481)
    { "Bernhard Reiter", I18N_NOOP("\xC3\x84gypten and Kroupware project management"),
      "bernhard@intevation.de", 0 },
    { "Edwin Schepers", 0, "yez@familieschepers.nl", 0 }, // composition of HTML messages
    { "Jakob Schr\303\266ter", 0, 0, 0 }, // implemented wish 28319 (X-Face support)
    { "Jan Simonson", I18N_NOOP("beta testing of PGP 6 support"),
      "jan@simonson.pp.se", 0 },
    { "Paul Sprakes", 0, 0, 0 }, // fix for bug:63619 (filter button in toolbar doesn't work), context menu clean up
    { "Will Stephenson", 0, 0, 0 }, // added IM status indicator
    { "Hasso Tepper", 0, 0, 0 }, // improve layout of recipients editor
    { "Patrick S. Vogt", I18N_NOOP("timestamp for 'Transmission completed' status messages"),
      "patrick.vogt@unibas.ch", 0 },
    { "Jan-Oliver Wagner", I18N_NOOP("\xC3\x84gypten and Kroupware project management"),
      "jan@intevation.de", 0 },
    { "Wolfgang Westphal", I18N_NOOP("multiple encryption keys per address"),
      "wolfgang.westphal@gmx.de", 0 },
    { "Thorsten Zachmann", I18N_NOOP("POP filters"),
      "t.zachmann@zagge.de", 0 },
    { "Thomas Zander", 0, 0, 0 }
  };

  AboutData::AboutData()
    : KAboutData( "kmail", 0, ki18n("KMail"),KMAIL_VERSION,
                  ki18n("KDE Email Client"), License_GPL,
                  ki18n("(c) 1997-2009, The KMail developers"), KLocalizedString(),
                  "http://kontact.kde.org/kmail/" )
  {
    using KMail::authors;
    using KMail::credits;
    for ( unsigned int i = 0 ; i < sizeof authors / sizeof *authors ; ++i )
      addAuthor( ki18n(authors[i].name), ki18n(authors[i].desc), authors[i].email, authors[i].web );
    for ( unsigned int i = 0 ; i < sizeof credits / sizeof *credits ; ++i )
      addCredit( ki18n(credits[i].name), ki18n(credits[i].desc), credits[i].email, credits[i].web );
  }

  AboutData::~AboutData() {

  }

} // namespace KMail
<|endoftext|>


<commit_before>#include "car.h"
#include "gtest/gtest.h"

namespace oop_project {

TEST(CarTest, InitializesDataMembers) {
  Segment segment;
  Car car(5, &segment);
  ASSERT_EQ(5, car.exit_junction());
  ASSERT_EQ(false, car.ready());
  ASSERT_EQ(&segment, car.segment());
}

TEST(CarTest, ReturnsExitJunction) {
  Car car(5, NULL);
  ASSERT_EQ(5, car.exit_junction());
}

TEST(CarTest, ReturnsReady) {
  Car car(5, NULL);
  ASSERT_EQ(false, car.ready());
}

TEST(CarTest, ReturnsSegment) {
  Segment segment;
  Car car(5, &segment);
  ASSERT_EQ(&segment, car.segment());
}

TEST(CarTest, ChangesReadyValue) {
  Car car(5, NULL);
  car.set_ready(true);
  ASSERT_EQ(true, car.ready());
  car.set_ready(false);
  ASSERT_EQ(false, car.ready());
}

TEST(CarTest, ChangesSegmentValue) {
  Segment segment;
  Car car(5, NULL);
  car.set_segment(&segment);
  ASSERT_EQ(&segment, car.segment());
}

}  // namespace oop_project
<commit_msg>Car: Changed test to match with Segment constructor<commit_after>#include "car.h"
#include "gtest/gtest.h"

namespace oop_project {

TEST(CarTest, InitializesDataMembers) {
  Segment segment(5, NULL, 5, 5, 5);
  Car car(5, &segment);
  ASSERT_EQ(5, car.exit_junction());
  ASSERT_EQ(false, car.ready());
  ASSERT_EQ(&segment, car.segment());
}

TEST(CarTest, ReturnsExitJunction) {
  Car car(5, NULL);
  ASSERT_EQ(5, car.exit_junction());
}

TEST(CarTest, ReturnsReady) {
  Car car(5, NULL);
  ASSERT_EQ(false, car.ready());
}

TEST(CarTest, ReturnsSegment) {
  Segment segment(5, NULL, 5, 5, 5);
  Car car(5, &segment);
  ASSERT_EQ(&segment, car.segment());
}

TEST(CarTest, ChangesReadyValue) {
  Car car(5, NULL);
  car.set_ready(true);
  ASSERT_EQ(true, car.ready());
  car.set_ready(false);
  ASSERT_EQ(false, car.ready());
}

TEST(CarTest, ChangesSegmentValue) {
  Segment segment(5, NULL, 5, 5, 5);
  Car car(5, NULL);
  car.set_segment(&segment);
  ASSERT_EQ(&segment, car.segment());
}

}  // namespace oop_project
<|endoftext|>