<commit_before>//=======================================================================
// Copyright (c) 2013-2020 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <tuple>
#include <utility>
#include <iostream>
#include <sstream>
#include <map>
#include <set>

#include "cpp_utils/string.hpp"

#include "share.hpp"
#include "assets.hpp"
#include "config.hpp"
#include "http.hpp"
#include "data.hpp"
#include "data_cache.hpp"
#include "date.hpp"
#include "money.hpp"
#include "server_lock.hpp"
#include "logging.hpp"

namespace {

struct share_price_cache_key {
    budget::date date;
    std::string ticker;

    share_price_cache_key(budget::date date, std::string ticker) : date(date), ticker(ticker) {}

    friend bool operator<(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) < std::tie(rhs.date, rhs.ticker);
    }

    friend bool operator==(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) == std::tie(rhs.date, rhs.ticker);
    }
};

std::map<share_price_cache_key, budget::money> share_prices;
budget::server_lock shares_lock;

budget::date get_valid_date(budget::date d){
    // We cannot get closing price in the future, so we use the day before date
    if (d >= budget::local_day()) {
        auto now = std::chrono::system_clock::now();
        auto tt  = std::chrono::system_clock::to_time_t(now);
        auto tm  = *std::localtime(&tt);

        // We make sure that we are on a new U.S: day
        // TODO This should be done by getting the current time in the U.S.
        if (tm.tm_hour > 15) {
            return get_valid_date(budget::local_day() - budget::days(1));
        } else {
            return get_valid_date(budget::local_day() - budget::days(2));
        }
    }

    auto dow = d.day_of_the_week();

    if (dow == 6 || dow == 7){
        return get_valid_date(d - budget::days(dow - 5));
    }

    return d;
}

std::string exec_command(const std::string& command) {
    std::stringstream output;

    char buffer[1024];

    FILE* stream = popen(command.c_str(), "r");

    while (fgets(buffer, 1024, stream) != NULL) {
        output << buffer;
    }

    pclose(stream);

    return output.str();
}

// V3 is using Yahoo Finance
// Starting from this version, the get_share_price function must be thread
// safe. This means, it cannot touch the cache itself
std::map<share_price_cache_key, budget::money> get_share_price_v3(const std::string & ticker, budget::date start_date, budget::date end_date) {
    std::string command = "yfinance_quote.py " + ticker + " " + date_to_string(start_date) + " " + date_to_string(end_date);

    auto result = exec_command(command);

    if (result.empty()) {
        LOG_F(ERROR, "Price(v3): yfinance_quote.py returned nothing");

        return {};
    }

    std::map<share_price_cache_key, budget::money> quotes;

    std::stringstream ss(result);

    try {
        std::string line;
        while (getline(ss, line)) {
            budget::data_reader reader;
            reader.parse(line);

            budget::date  d;
            budget::money m;

            reader >> d;
            reader >> m;

            share_price_cache_key key(d, ticker);
            quotes[key] = m;
        }
    } catch (const budget::date_exception& e) {
        return {};
    } catch (const budget::budget_exception& e) {
        return {};
    }

    return quotes;
}

} // end of anonymous namespace

void budget::load_share_price_cache(){
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ifstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to load Share Price Cache");
        return;
    }

    std::string line;
    while (file.good() && getline(file, line)) {
        if (line.empty()) {
            continue;
        }

        // Note: For now, we still need to use double instead of money since
        // previous data was written in an invalid format related to money
        // However, this will be able to go away since they are written down
        // with budget::money now

        budget::date day;
        std::string  ticker;
        double       value;

        data_reader reader;
        reader.parse(line);

        reader >> day;
        reader >> ticker;
        reader >> value;

        share_price_cache_key key(day, ticker);
        share_prices[key] = budget::money::from_double(value);
    }

    LOG_F(INFO, "Share Price Cache has been loaded from {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::save_share_price_cache() {
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ofstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to save Share Price Cache");
        return;
    }

    {
        server_lock_guard l(shares_lock);

        for (auto& [key, value] : share_prices) {
            if (value != budget::money(1)) {
                data_writer writer;
                writer << key.date;
                writer << key.ticker;
                writer << value;
                file << writer.to_string() << std::endl;
            }
        }
    }

    LOG_F(INFO, "Share Price Cache has been saved to {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::prefetch_share_price_cache(){
    std::set<std::string> tickers;

    {
        server_lock_guard l(shares_lock);

        // Collect all the tickers
        for (auto& [key, value] : share_prices) {
            tickers.insert(key.ticker);
        }
    }

    data_cache cache;

    // Prefetch the current prices
    for (auto & ticker : tickers) {
        if (is_ticker_active(cache, ticker)) {
            share_price(ticker);
        }
    }

    LOG_F(INFO, "Share Price Cache has been prefetched");
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

budget::money budget::share_price(const std::string& ticker){
    return share_price(ticker, budget::local_day());
}

budget::money budget::share_price(const std::string& ticker, budget::date d){
    auto date = get_valid_date(d);

    share_price_cache_key key(date, ticker);

    {
        server_lock_guard l(shares_lock);

        if (share_prices.count(key)) {
            return share_prices[key];
        }
    }

    // Note: we use a range for two reasons
    // 1) Handle potential holidays, so we have a range in the past
    // 2) Opportunistically grab several quotes in the past and future to save on API calls
    auto start_date = d - budget::days(10);
    auto end_date   = d + budget::days(10);
    auto quotes     = get_share_price_v3(ticker, start_date, end_date);

    server_lock_guard l(shares_lock);

    // If the API did not find anything, it must mean that the ticker is
    // invalid
    if (quotes.empty()) {
        LOG_F(ERROR,
              "Price: Could not find quotes for {} for date {} ({}-{})",
              ticker,
              budget::to_string(d),
              budget::to_string(start_date),
              budget::to_string(end_date));

        share_prices[key] = money(1);
        return money(1);
    }

    for (auto [new_key, new_value] : quotes) {
        share_prices[new_key] = new_value;
    }

    // If it has not been found, it may be a holiday, so we try to get
    // back in time to find a proper value
    if (!share_prices.count(key)) {
        for (size_t i = 0; i < 4; ++i){
            auto next_date = get_valid_date(date - budget::days(1));

            LOG_F(INFO, "Price: Possible holiday on {}, retrying on {}", budget::to_string(date), budget::to_string(next_date));

            share_price_cache_key next_key(next_date, ticker);
            if (share_prices.count(next_key)) {
                share_prices[key] = share_prices[next_key];
                break;
            }
        }
    }

    if (!share_prices.count(key)) {
        LOG_F(ERROR, "Price: Unable to find data for {} on {}", ticker, budget::to_string(date));
        share_prices[key] = money(1);
        return money(1);
    }

    LOG_F(INFO, "Price: Share price ({}) ticker {} = {}", budget::to_string(date), ticker, budget::to_string(share_prices[key]));

    return share_prices[key];
}
<commit_msg>Better handling of invalid values in share cache<commit_after>//=======================================================================
// Copyright (c) 2013-2020 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <tuple>
#include <utility>
#include <iostream>
#include <sstream>
#include <map>
#include <set>

#include "cpp_utils/string.hpp"

#include "share.hpp"
#include "assets.hpp"
#include "config.hpp"
#include "http.hpp"
#include "data.hpp"
#include "data_cache.hpp"
#include "date.hpp"
#include "money.hpp"
#include "server_lock.hpp"
#include "logging.hpp"

namespace {

struct share_price_cache_key {
    budget::date date;
    std::string ticker;

    share_price_cache_key(budget::date date, std::string ticker) : date(date), ticker(ticker) {}

    friend bool operator<(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) < std::tie(rhs.date, rhs.ticker);
    }

    friend bool operator==(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) == std::tie(rhs.date, rhs.ticker);
    }
};

// We use a struct so that we can store values of 1 that can indicate either
// a valid value or an invalid one
// Without that, we could not store values of 1 in the cache file
struct share_cache_value {
    budget::money value;
    bool   valid;
};

std::map<share_price_cache_key, share_cache_value> share_prices;
budget::server_lock shares_lock;

budget::date get_valid_date(budget::date d){
    // We cannot get closing price in the future, so we use the day before date
    if (d >= budget::local_day()) {
        auto now = std::chrono::system_clock::now();
        auto tt  = std::chrono::system_clock::to_time_t(now);
        auto tm  = *std::localtime(&tt);

        // We make sure that we are on a new U.S: day
        // TODO This should be done by getting the current time in the U.S.
        if (tm.tm_hour > 15) {
            return get_valid_date(budget::local_day() - budget::days(1));
        } else {
            return get_valid_date(budget::local_day() - budget::days(2));
        }
    }

    auto dow = d.day_of_the_week();

    if (dow == 6 || dow == 7){
        return get_valid_date(d - budget::days(dow - 5));
    }

    return d;
}

std::string exec_command(const std::string& command) {
    std::stringstream output;

    char buffer[1024];

    FILE* stream = popen(command.c_str(), "r");

    while (fgets(buffer, 1024, stream) != NULL) {
        output << buffer;
    }

    pclose(stream);

    return output.str();
}

// V3 is using Yahoo Finance
// Starting from this version, the get_share_price function must be thread
// safe. This means, it cannot touch the cache itself
std::map<share_price_cache_key, budget::money> get_share_price_v3(const std::string & ticker, budget::date start_date, budget::date end_date) {
    std::string command = "yfinance_quote.py " + ticker + " " + date_to_string(start_date) + " " + date_to_string(end_date);

    auto result = exec_command(command);

    if (result.empty()) {
        LOG_F(ERROR, "Price(v3): yfinance_quote.py returned nothing");

        return {};
    }

    std::map<share_price_cache_key, budget::money> quotes;

    std::stringstream ss(result);

    try {
        std::string line;
        while (getline(ss, line)) {
            budget::data_reader reader;
            reader.parse(line);

            budget::date  d;
            budget::money m;

            reader >> d;
            reader >> m;

            share_price_cache_key key(d, ticker);
            quotes[key] = m;
        }
    } catch (const budget::date_exception& e) {
        return {};
    } catch (const budget::budget_exception& e) {
        return {};
    }

    return quotes;
}

} // end of anonymous namespace

void budget::load_share_price_cache(){
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ifstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to load Share Price Cache");
        return;
    }

    std::string line;
    while (file.good() && getline(file, line)) {
        if (line.empty()) {
            continue;
        }

        // Note: For now, we still need to use double instead of money since
        // previous data was written in an invalid format related to money
        // However, this will be able to go away since they are written down
        // with budget::money now

        budget::date day;
        std::string  ticker;
        double       value;

        data_reader reader;
        reader.parse(line);

        reader >> day;
        reader >> ticker;
        reader >> value;

        share_price_cache_key key(day, ticker);
        share_prices[key] = {budget::money::from_double(value), true};
    }

    LOG_F(INFO, "Share Price Cache has been loaded from {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::save_share_price_cache() {
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ofstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to save Share Price Cache");
        return;
    }

    {
        server_lock_guard l(shares_lock);

        for (auto& [key, value] : share_prices) {
            if (value.valid) {
                data_writer writer;
                writer << key.date;
                writer << key.ticker;
                writer << value.value;
                file << writer.to_string() << std::endl;
            }
        }
    }

    LOG_F(INFO, "Share Price Cache has been saved to {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::prefetch_share_price_cache(){
    std::set<std::string> tickers;

    {
        server_lock_guard l(shares_lock);

        // Collect all the tickers
        for (auto& [key, value] : share_prices) {
            tickers.insert(key.ticker);
        }
    }

    data_cache cache;

    // Prefetch the current prices
    for (auto & ticker : tickers) {
        if (is_ticker_active(cache, ticker)) {
            share_price(ticker);
        }
    }

    LOG_F(INFO, "Share Price Cache has been prefetched");
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

budget::money budget::share_price(const std::string& ticker){
    return share_price(ticker, budget::local_day());
}

budget::money budget::share_price(const std::string& ticker, budget::date d){
    auto date = get_valid_date(d);

    share_price_cache_key key(date, ticker);

    // The first step is to get the data from the cache

    {
        server_lock_guard l(shares_lock);

        if (share_prices.count(key)) {
            return share_prices[key].value;
        }
    }

    // Note: we use a range for two reasons
    // 1) Handle potential holidays, so we have a range in the past
    // 2) Opportunistically grab several quotes in the past and future to save on API calls
    auto start_date = d - budget::days(10);
    auto end_date   = d + budget::days(10);
    auto quotes     = get_share_price_v3(ticker, start_date, end_date);

    server_lock_guard l(shares_lock);

    // If the API did not find anything, it must mean that the ticker is
    // invalid
    if (quotes.empty()) {
        LOG_F(ERROR,
              "Price: Could not find quotes for {} for date {} ({}-{})",
              ticker,
              budget::to_string(d),
              budget::to_string(start_date),
              budget::to_string(end_date));

        share_prices[key] = {money(1), false};
        return money(1);
    }

    for (auto [new_key, new_value] : quotes) {
        share_prices[new_key] = {new_value, true};
    }

    // If it has not been found, it may be a holiday, so we try to get
    // back in time to find a proper value
    if (!share_prices.count(key)) {
        for (size_t i = 0; i < 4; ++i){
            auto next_date = get_valid_date(date - budget::days(1));

            LOG_F(INFO, "Price: Possible holiday on {}, retrying on {}", budget::to_string(date), budget::to_string(next_date));

            share_price_cache_key next_key(next_date, ticker);
            if (share_prices.count(next_key)) {
                share_prices[key] = share_prices[next_key];
                break;
            }
        }
    }

    if (!share_prices.count(key)) {
        LOG_F(ERROR, "Price: Unable to find data for {} on {}", ticker, budget::to_string(date));
        share_prices[key] = {money(1), false};
        return money(1);
    }

    LOG_F(INFO, "Price: Share price ({}) ticker {} = {}", budget::to_string(date), ticker, budget::to_string(share_prices[key].value));

    return share_prices[key].value;
}
<|endoftext|>


<commit_before>/** openrtb_bid_source.cc                                 -*- C++ -*-
    Eric Robert, 13 Aug 2013
    Copyright (c) 2013 Datacratic.  All rights reserved.

*/

#include "openrtb_bid_source.h"
#include "openrtb_bid_request.h"
#include "rtbkit/openrtb/openrtb_parsing.h"
#include "soa/service/http_header.h"
#include <mutex>

using namespace Datacratic;
using namespace RTBKIT;

namespace {
    class BidRequestReplayBuffer {
    public:
        BidRequestReplayBuffer() :
            cursor { 0 }
          , isFileLoaded { false }
        { }

        void loadFile(const std::string &fileName) {
            JML_TRACE_EXCEPTIONS(false)
            ML::filter_istream is(fileName);
            if (!is) {
                throw ML::Exception(ML::format("Could not load replay file: %s",
                                               fileName.c_str()));
            }

            std::cout << "Loading " << fileName << " replay file" << std::endl;

            size_t rejected, total;
            rejected = total = 0;
            for (std::string line; getline(is, line); ) {
                try {
                    ++total;
                    auto br = OpenRtbBidRequestParser::parseBidRequest(line);
                    buffer.push_back(std::move(br));
                } catch (const ML::Exception &) {
                    ++rejected;
                }
            }

            std::cout << "Replay: parsed total of " << total << " lines, "
                      << rejected << " rejected (" << ((rejected * 100.0) / total)
                      << "%)" << std::endl;
            isFileLoaded = true;

        }

        OpenRTB::BidRequest next() {
            // Spinning until isFileLoaded is true
            while (!isFileLoaded) ;

            size_t index = cursor.load();
            ExcCheck(index < buffer.size(), "replayCursor is invalid");

            auto br = buffer[index];
            size_t oldIndex { index };
            size_t newIndex;
            do {
                newIndex = (oldIndex + 1) % buffer.size();
            } while (!cursor.compare_exchange_weak(oldIndex, newIndex));

            return br;
        }

    private:
        std::atomic<size_t> cursor;
        std::atomic<bool> isFileLoaded;
        std::vector<OpenRTB::BidRequest> buffer;
    };

    BidRequestReplayBuffer replay;
    std::once_flag flag;
}

OpenRTBBidSource::
OpenRTBBidSource(Json::Value const & json) :
    BidSource(json),
    host(json.get("host", ML::hostname()).asString()),
    verb(json.get("verb", "POST").asString()),
    resource(json.get("resource", "/").asString())
{
    std::call_once(flag, [&]() {
        if (json.isMember("replayFile")) {
            replayFile = true;
            replay.loadFile(json["replayFile"].asString());
        }
    });
}

OpenRTB::BidRequest
OpenRTBBidSource::
generateRequest()
{
    key += rng.random();

    OpenRTB::BidRequest req;
    req.id = Id(rng.random());
    req.tmax.val = 50;
    req.at = AuctionType::SECOND_PRICE;
    req.imp.emplace_back();
    auto & imp = req.imp[0];
    imp.id = Id(key);
    imp.banner.reset(new OpenRTB::Banner);
    imp.banner->w.push_back(300);
    imp.banner->h.push_back(250);

    return req;
}

BidRequest OpenRTBBidSource::generateRandomBidRequest() {
    OpenRTB::BidRequest req;

    if (replayFile)
        req = replay.next();
    else
        req = generateRequest();

    StructuredJsonPrintingContext context;
    DefaultDescription<OpenRTB::BidRequest> desc;
    desc.printJson(&req, context);
    std::string content = context.output.toString();

    int length = content.length();

    std::string message = ML::format(
        "%s %s HTTP/1.1\r\n"
        "Content-Type: application/json\r\n"
        "Content-Length: %d\r\n"
        "accept: */*\r\n"
        "connection: Keep-Alive\r\n"
        "host: %s\r\n"
        "user-agent: be2/1.0\r\n"
        "x-openrtb-version: 2.1\r\n"
        "\r\n%s",
        verb.c_str(), resource.c_str(), length, host.c_str(), content.c_str());

    write(message);
    std::unique_ptr<BidRequest> br(fromOpenRtb(std::move(req), "openrtb", "openrtb"));
    return BidRequest(*br);
}

auto
OpenRTBBidSource::
parseResponse(const std::string& rawResponse) -> std::pair<bool, std::vector<Bid>> {
    OpenRTB::BidResponse response;

    if(rawResponse.empty()) {
        return std::make_pair(false, std::vector<Bid>());
    }

    try {
        HttpHeader header;
        header.parse(rawResponse);
        if (!header.contentLength || header.resource != "200") {
            //std::cerr << rawResponse << std::endl;
            return std::make_pair(false, std::vector<Bid>());
        }

        ML::Parse_Context context("payload", header.knownData.c_str(), header.knownData.size());
        StreamingJsonParsingContext json(context);
        DefaultDescription<OpenRTB::BidResponse> desc;
        desc.parseJson(&response, json);
    }
    catch (const std::exception & exc) {
        std::cerr << "invalid response received: " << exc.what() << std::endl;
        return std::make_pair(false, std::vector<Bid>());
    }

    std::vector<Bid> bids;

    for(auto i = 0; i != response.seatbid[0].bid.size(); ++i) {
        Bid bid;
        bid.adSpotId = response.seatbid[0].bid[i].impid;
        bid.maxPrice = USD_CPM(response.seatbid[0].bid[i].price.val);
        bids.push_back(bid);
    }

    return std::make_pair(true, bids);
}

namespace {

struct AtInit {
    AtInit()
    {
        BidSource::registerBidSourceFactory("openrtb", [](Json::Value const & json) {
            return new OpenRTBBidSource(json);
        });
    }
} atInit;

}

<commit_msg>Randomizing BidRequest id and impressions id to avoid duplicate auction ids when sending replay BidRequest<commit_after>/** openrtb_bid_source.cc                                 -*- C++ -*-
    Eric Robert, 13 Aug 2013
    Copyright (c) 2013 Datacratic.  All rights reserved.

*/

#include "openrtb_bid_source.h"
#include "openrtb_bid_request.h"
#include "rtbkit/openrtb/openrtb_parsing.h"
#include "soa/service/http_header.h"
#include <mutex>

using namespace Datacratic;
using namespace RTBKIT;

namespace {
    class BidRequestReplayBuffer {
    public:
        BidRequestReplayBuffer() :
            cursor { 0 }
          , isFileLoaded { false }
        { }

        void loadFile(const std::string &fileName) {
            JML_TRACE_EXCEPTIONS(false)
            ML::filter_istream is(fileName);
            if (!is) {
                throw ML::Exception(ML::format("Could not load replay file: %s",
                                               fileName.c_str()));
            }

            std::cout << "Loading " << fileName << " replay file" << std::endl;

            size_t rejected, total;
            rejected = total = 0;
            for (std::string line; getline(is, line); ) {
                try {
                    ++total;
                    auto br = OpenRtbBidRequestParser::parseBidRequest(line);
                    buffer.push_back(std::move(br));
                } catch (const ML::Exception &) {
                    ++rejected;
                }
            }

            std::cout << "Replay: parsed total of " << total << " lines, "
                      << rejected << " rejected (" << ((rejected * 100.0) / total)
                      << "%)" << std::endl;
            isFileLoaded = true;

        }

        OpenRTB::BidRequest next() {
            // Spinning until isFileLoaded is true
            while (!isFileLoaded) ;

            size_t index = cursor.load();
            ExcCheck(index < buffer.size(), "replayCursor is invalid");

            auto br = buffer[index];
            size_t oldIndex { index };
            size_t newIndex;
            do {
                newIndex = (oldIndex + 1) % buffer.size();
            } while (!cursor.compare_exchange_weak(oldIndex, newIndex));

            return br;
        }

    private:
        std::atomic<size_t> cursor;
        std::atomic<bool> isFileLoaded;
        std::vector<OpenRTB::BidRequest> buffer;
    };

    BidRequestReplayBuffer replay;
    std::once_flag flag;
}

OpenRTBBidSource::
OpenRTBBidSource(Json::Value const & json) :
    BidSource(json),
    host(json.get("host", ML::hostname()).asString()),
    verb(json.get("verb", "POST").asString()),
    resource(json.get("resource", "/").asString())
{
    std::call_once(flag, [&]() {
        if (json.isMember("replayFile")) {
            replayFile = true;
            replay.loadFile(json["replayFile"].asString());
        }
    });
}

OpenRTB::BidRequest
OpenRTBBidSource::
generateRequest()
{
    key += rng.random();

    OpenRTB::BidRequest req;
    req.id = Id(rng.random());
    req.tmax.val = 50;
    req.at = AuctionType::SECOND_PRICE;
    req.imp.emplace_back();
    auto & imp = req.imp[0];
    imp.id = Id(key);
    imp.banner.reset(new OpenRTB::Banner);
    imp.banner->w.push_back(300);
    imp.banner->h.push_back(250);

    return req;
}

BidRequest OpenRTBBidSource::generateRandomBidRequest() {
    OpenRTB::BidRequest req;

    if (replayFile) {
        req = replay.next();
        req.id = Id(rng.random());
        for (auto &imp: req.imp) {
            key += rng.random();
            imp.id = Id(key);
        }
    }
    else {
        req = generateRequest();
    }

    StructuredJsonPrintingContext context;
    DefaultDescription<OpenRTB::BidRequest> desc;
    desc.printJson(&req, context);
    std::string content = context.output.toString();

    int length = content.length();

    std::string message = ML::format(
        "%s %s HTTP/1.1\r\n"
        "Content-Type: application/json\r\n"
        "Content-Length: %d\r\n"
        "accept: */*\r\n"
        "connection: Keep-Alive\r\n"
        "host: %s\r\n"
        "user-agent: be2/1.0\r\n"
        "x-openrtb-version: 2.1\r\n"
        "\r\n%s",
        verb.c_str(), resource.c_str(), length, host.c_str(), content.c_str());

    write(message);
    std::unique_ptr<BidRequest> br(fromOpenRtb(std::move(req), "openrtb", "openrtb"));
    return BidRequest(*br);
}

auto
OpenRTBBidSource::
parseResponse(const std::string& rawResponse) -> std::pair<bool, std::vector<Bid>> {
    OpenRTB::BidResponse response;

    if(rawResponse.empty()) {
        return std::make_pair(false, std::vector<Bid>());
    }

    try {
        HttpHeader header;
        header.parse(rawResponse);
        if (!header.contentLength || header.resource != "200") {
            //std::cerr << rawResponse << std::endl;
            return std::make_pair(false, std::vector<Bid>());
        }

        ML::Parse_Context context("payload", header.knownData.c_str(), header.knownData.size());
        StreamingJsonParsingContext json(context);
        DefaultDescription<OpenRTB::BidResponse> desc;
        desc.parseJson(&response, json);
    }
    catch (const std::exception & exc) {
        std::cerr << "invalid response received: " << exc.what() << std::endl;
        return std::make_pair(false, std::vector<Bid>());
    }

    std::vector<Bid> bids;

    for(auto i = 0; i != response.seatbid[0].bid.size(); ++i) {
        Bid bid;
        bid.adSpotId = response.seatbid[0].bid[i].impid;
        bid.maxPrice = USD_CPM(response.seatbid[0].bid[i].price.val);
        bids.push_back(bid);
    }

    return std::make_pair(true, bids);
}

namespace {

struct AtInit {
    AtInit()
    {
        BidSource::registerBidSourceFactory("openrtb", [](Json::Value const & json) {
            return new OpenRTBBidSource(json);
        });
    }
} atInit;

}

<|endoftext|>


<commit_before><commit_msg>Fix coverity reports (dereference null return values)<commit_after><|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2013-2020 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <tuple>
#include <utility>
#include <iostream>
#include <sstream>
#include <map>
#include <set>

#include "cpp_utils/string.hpp"

#include "share.hpp"
#include "assets.hpp"
#include "config.hpp"
#include "http.hpp"
#include "data.hpp"
#include "data_cache.hpp"
#include "date.hpp"
#include "money.hpp"
#include "server_lock.hpp"
#include "logging.hpp"

namespace {

struct share_price_cache_key {
    budget::date date;
    std::string ticker;

    share_price_cache_key(budget::date date, std::string ticker) : date(date), ticker(ticker) {}

    friend bool operator<(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) < std::tie(rhs.date, rhs.ticker);
    }

    friend bool operator==(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) == std::tie(rhs.date, rhs.ticker);
    }
};

// We use a struct so that we can store values of 1 that can indicate either
// a valid value or an invalid one
// Without that, we could not store values of 1 in the cache file
struct share_cache_value {
    budget::money value;
    bool   valid;
};

std::map<share_price_cache_key, share_cache_value> share_prices;
budget::server_lock shares_lock;

budget::date get_valid_date(budget::date d){
    // We cannot get closing price in the future, so we use the day before date
    if (d >= budget::local_day()) {
        auto now = std::chrono::system_clock::now();
        auto tt  = std::chrono::system_clock::to_time_t(now);
        auto tm  = *std::localtime(&tt);

        // We make sure that we are on a new U.S: day
        // TODO This should be done by getting the current time in the U.S.
        if (tm.tm_hour > 15) {
            return get_valid_date(budget::local_day() - budget::days(1));
        } else {
            return get_valid_date(budget::local_day() - budget::days(2));
        }
    }

    auto dow = d.day_of_the_week();

    if (dow == 6 || dow == 7){
        return get_valid_date(d - budget::days(dow - 5));
    }

    return d;
}

std::string exec_command(const std::string& command) {
    std::stringstream output;

    char buffer[1024];

    FILE* stream = popen(command.c_str(), "r");

    while (fgets(buffer, 1024, stream) != NULL) {
        output << buffer;
    }

    pclose(stream);

    return output.str();
}

// V3 is using Yahoo Finance
// Starting from this version, the get_share_price function must be thread
// safe. This means, it cannot touch the cache itself
std::map<share_price_cache_key, budget::money> get_share_price_v3(const std::string & ticker, budget::date start_date, budget::date end_date) {
    std::string command = "yfinance_quote.py " + ticker + " " + date_to_string(start_date) + " " + date_to_string(end_date);

    auto result = exec_command(command);

    if (result.empty()) {
        LOG_F(ERROR, "Price(v3): yfinance_quote.py returned nothing");

        return {};
    }

    std::map<share_price_cache_key, budget::money> quotes;

    std::stringstream ss(result);

    try {
        std::string line;
        while (getline(ss, line)) {
            budget::data_reader reader;
            reader.parse(line);

            budget::date  d;
            budget::money m;

            reader >> d;
            reader >> m;

            share_price_cache_key key(d, ticker);
            quotes[key] = m;
        }
    } catch (const budget::date_exception& e) {
        return {};
    } catch (const budget::budget_exception& e) {
        return {};
    }

    return quotes;
}

} // end of anonymous namespace

void budget::load_share_price_cache(){
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ifstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to load Share Price Cache");
        return;
    }

    std::string line;
    while (file.good() && getline(file, line)) {
        if (line.empty()) {
            continue;
        }

        // Note: For now, we still need to use double instead of money since
        // previous data was written in an invalid format related to money
        // However, this will be able to go away since they are written down
        // with budget::money now

        budget::date day;
        std::string  ticker;
        double       value;

        data_reader reader;
        reader.parse(line);

        reader >> day;
        reader >> ticker;
        reader >> value;

        share_price_cache_key key(day, ticker);
        share_prices[key] = {budget::money::from_double(value), true};
    }

    LOG_F(INFO, "Share Price Cache has been loaded from {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::save_share_price_cache() {
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ofstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to save Share Price Cache");
        return;
    }

    {
        server_lock_guard l(shares_lock);

        for (auto& [key, value] : share_prices) {
            if (value.valid) {
                data_writer writer;
                writer << key.date;
                writer << key.ticker;
                writer << value.value;
                file << writer.to_string() << std::endl;
            }
        }
    }

    LOG_F(INFO, "Share Price Cache has been saved to {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::prefetch_share_price_cache(){
    std::set<std::string> tickers;

    {
        server_lock_guard l(shares_lock);

        // Collect all the tickers
        for (auto& [key, value] : share_prices) {
            tickers.insert(key.ticker);
        }
    }

    data_cache cache;

    // Prefetch the current prices
    for (auto & ticker : tickers) {
        if (is_ticker_active(cache, ticker)) {
            share_price(ticker);
        }
    }

    LOG_F(INFO, "Share Price Cache has been prefetched");
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

budget::money budget::share_price(const std::string& ticker){
    return share_price(ticker, budget::local_day());
}

budget::money budget::share_price(const std::string& ticker, budget::date d){
    auto date = get_valid_date(d);

    share_price_cache_key key(date, ticker);

    // The first step is to get the data from the cache

    {
        server_lock_guard l(shares_lock);

        if (share_prices.count(key)) {
            return share_prices[key].value;
        }
    }

    // Note: we use a range for two reasons
    // 1) Handle potential holidays, so we have a range in the past
    // 2) Opportunistically grab several quotes in the past and future to save on API calls
    auto start_date = d - budget::days(10);
    auto end_date   = d + budget::days(10);
    auto quotes     = get_share_price_v3(ticker, start_date, end_date);

    server_lock_guard l(shares_lock);

    // If the API did not find anything, it must mean that the ticker is
    // invalid
    if (quotes.empty()) {
        LOG_F(ERROR,
              "Price: Could not find quotes for {} for date {} ({}-{})",
              ticker,
              budget::to_string(d),
              budget::to_string(start_date),
              budget::to_string(end_date));

        share_prices[key] = {money(1), false};
        return money(1);
    }

    for (auto [new_key, new_value] : quotes) {
        share_prices[new_key] = {new_value, true};
    }

    // If it has not been found, it may be a holiday, so we try to get
    // back in time to find a proper value
    if (!share_prices.count(key)) {
        for (size_t i = 0; i < 4; ++i){
            auto next_date = get_valid_date(date - budget::days(1));

            LOG_F(INFO, "Price: Possible holiday on {}, retrying on {}", budget::to_string(date), budget::to_string(next_date));

            share_price_cache_key next_key(next_date, ticker);
            if (share_prices.count(next_key)) {
                share_prices[key] = share_prices[next_key];
                break;
            }
        }
    }

    if (!share_prices.count(key)) {
        LOG_F(ERROR, "Price: Unable to find data for {} on {}", ticker, budget::to_string(date));
        share_prices[key] = {money(1), false};
        return money(1);
    }

    LOG_F(INFO, "Price: Share price ({}) ticker {} = {}", budget::to_string(date), ticker, budget::to_string(share_prices[key].value));

    return share_prices[key].value;
}
<commit_msg>Better handling of missing values<commit_after>//=======================================================================
// Copyright (c) 2013-2020 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <tuple>
#include <utility>
#include <iostream>
#include <sstream>
#include <map>
#include <set>

#include "cpp_utils/string.hpp"

#include "share.hpp"
#include "assets.hpp"
#include "config.hpp"
#include "http.hpp"
#include "data.hpp"
#include "data_cache.hpp"
#include "date.hpp"
#include "money.hpp"
#include "server_lock.hpp"
#include "logging.hpp"

namespace {

struct share_price_cache_key {
    budget::date date;
    std::string ticker;

    share_price_cache_key(budget::date date, std::string ticker) : date(date), ticker(ticker) {}

    friend bool operator<(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) < std::tie(rhs.date, rhs.ticker);
    }

    friend bool operator==(const share_price_cache_key & lhs, const share_price_cache_key & rhs){
        return std::tie(lhs.date, lhs.ticker) == std::tie(rhs.date, rhs.ticker);
    }
};

// We use a struct so that we can store values of 1 that can indicate either
// a valid value or an invalid one
// Without that, we could not store values of 1 in the cache file
struct share_cache_value {
    budget::money value;
    bool   valid;
};

std::map<share_price_cache_key, share_cache_value> share_prices;
budget::server_lock shares_lock;

budget::date get_valid_date(budget::date d){
    // We cannot get closing price in the future, so we use the day before date
    if (d >= budget::local_day()) {
        auto now = std::chrono::system_clock::now();
        auto tt  = std::chrono::system_clock::to_time_t(now);
        auto tm  = *std::localtime(&tt);

        // We make sure that we are on a new U.S: day
        // TODO This should be done by getting the current time in the U.S.
        if (tm.tm_hour > 15) {
            return get_valid_date(budget::local_day() - budget::days(1));
        } else {
            return get_valid_date(budget::local_day() - budget::days(2));
        }
    }

    auto dow = d.day_of_the_week();

    if (dow == 6 || dow == 7){
        return get_valid_date(d - budget::days(dow - 5));
    }

    return d;
}

// When we do not find a value for a ticker, we need to find an invalid value
// In the worst case, we use a value of 1, but sometimes we can do better
// We can try to find the closest date in the past for this ticker
// This function must be called with a lock!
share_cache_value get_invalid_value(share_price_cache_key key) {
    auto next_key = key;
    for (size_t i = 0; i < 5; ++i) {
        next_key.date = next_key.date - budget::days(1);

        if (share_prices.count(next_key)) {
            LOG_F(INFO,
                  "Price: Using invalid previous share price ({}->{}) for {} = {}",
                  budget::to_string(key.date),
                  budget::to_string(next_key.date),
                  key.ticker,
                  budget::to_string(share_prices[next_key].value));
            return {share_prices[next_key].value, false};
        }
    }

    LOG_F(INFO, "Price: Using invalid fixed share price ({}) for {} = 1", budget::to_string(key.date), key.ticker);

    return {budget::money(1), false};
}

std::string exec_command(const std::string& command) {
    std::stringstream output;

    char buffer[1024];

    FILE* stream = popen(command.c_str(), "r");

    while (fgets(buffer, 1024, stream) != NULL) {
        output << buffer;
    }

    pclose(stream);

    return output.str();
}

// V3 is using Yahoo Finance
// Starting from this version, the get_share_price function must be thread
// safe. This means, it cannot touch the cache itself
std::map<share_price_cache_key, budget::money> get_share_price_v3(const std::string & ticker, budget::date start_date, budget::date end_date) {
    std::string command = "yfinance_quote.py " + ticker + " " + date_to_string(start_date) + " " + date_to_string(end_date);

    auto result = exec_command(command);

    if (result.empty()) {
        LOG_F(ERROR, "Price(v3): yfinance_quote.py returned nothing");

        return {};
    }

    std::map<share_price_cache_key, budget::money> quotes;

    std::stringstream ss(result);

    try {
        std::string line;
        while (getline(ss, line)) {
            budget::data_reader reader;
            reader.parse(line);

            budget::date  d;
            budget::money m;

            reader >> d;
            reader >> m;

            share_price_cache_key key(d, ticker);
            quotes[key] = m;
        }
    } catch (const budget::date_exception& e) {
        return {};
    } catch (const budget::budget_exception& e) {
        return {};
    }

    return quotes;
}

} // end of anonymous namespace

void budget::load_share_price_cache(){
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ifstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to load Share Price Cache");
        return;
    }

    std::string line;
    while (file.good() && getline(file, line)) {
        if (line.empty()) {
            continue;
        }

        // Note: For now, we still need to use double instead of money since
        // previous data was written in an invalid format related to money
        // However, this will be able to go away since they are written down
        // with budget::money now

        budget::date day;
        std::string  ticker;
        double       value;

        data_reader reader;
        reader.parse(line);

        reader >> day;
        reader >> ticker;
        reader >> value;

        share_price_cache_key key(day, ticker);
        share_prices[key] = {budget::money::from_double(value), true};
    }

    LOG_F(INFO, "Share Price Cache has been loaded from {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::save_share_price_cache() {
    std::string file_path = budget::path_to_budget_file("share_price.cache");
    std::ofstream file(file_path);

    if (!file.is_open() || !file.good()){
        LOG_F(INFO, "Impossible to save Share Price Cache");
        return;
    }

    {
        server_lock_guard l(shares_lock);

        for (auto& [key, value] : share_prices) {
            if (value.valid) {
                data_writer writer;
                writer << key.date;
                writer << key.ticker;
                writer << value.value;
                file << writer.to_string() << std::endl;
            }
        }
    }

    LOG_F(INFO, "Share Price Cache has been saved to {}", file_path);
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

void budget::prefetch_share_price_cache(){
    std::set<std::string> tickers;

    {
        server_lock_guard l(shares_lock);

        // Collect all the tickers
        for (auto& [key, value] : share_prices) {
            tickers.insert(key.ticker);
        }
    }

    data_cache cache;

    // Prefetch the current prices
    for (auto & ticker : tickers) {
        if (is_ticker_active(cache, ticker)) {
            share_price(ticker);
        }
    }

    LOG_F(INFO, "Share Price Cache has been prefetched");
    LOG_F(INFO, "Share Price Cache has {} entries", share_prices.size());
}

budget::money budget::share_price(const std::string& ticker){
    return share_price(ticker, budget::local_day());
}

budget::money budget::share_price(const std::string& ticker, budget::date d){
    auto date = get_valid_date(d);

    share_price_cache_key key(date, ticker);

    // The first step is to get the data from the cache

    {
        server_lock_guard l(shares_lock);

        if (share_prices.count(key)) {
            return share_prices[key].value;
        }
    }

    // Note: we use a range for two reasons
    // 1) Handle potential holidays, so we have a range in the past
    // 2) Opportunistically grab several quotes in the past and future to save on API calls
    auto start_date = d - budget::days(10);
    auto end_date   = d + budget::days(10);
    auto quotes     = get_share_price_v3(ticker, start_date, end_date);

    server_lock_guard l(shares_lock);

    // If the API did not find anything, it must mean that the ticker is
    // invalid
    if (quotes.empty()) {
        LOG_F(ERROR,
              "Price: Could not find quotes for {} for date {} ({}-{})",
              ticker,
              budget::to_string(d),
              budget::to_string(start_date),
              budget::to_string(end_date));

        share_prices[key] = get_invalid_value(key);
        return share_prices[key].value;
    }

    for (auto [new_key, new_value] : quotes) {
        share_prices[new_key] = {new_value, true};
    }

    // If it has not been found, it may be a holiday, so we try to get
    // back in time to find a proper value
    if (!share_prices.count(key)) {
        for (size_t i = 0; i < 4; ++i){
            auto next_date = get_valid_date(date - budget::days(1));

            LOG_F(INFO, "Price: Possible holiday on {}, retrying on {}", budget::to_string(date), budget::to_string(next_date));

            share_price_cache_key next_key(next_date, ticker);
            if (share_prices.count(next_key)) {
                share_prices[key] = share_prices[next_key];
                break;
            }
        }
    }

    if (!share_prices.count(key)) {
        LOG_F(ERROR, "Price: Unable to find data for {} on {}", ticker, budget::to_string(date));
        share_prices[key] = get_invalid_value(key);
        return share_prices[key].value;
    }

    LOG_F(INFO, "Price: Share price ({}) ticker {} = {}", budget::to_string(date), ticker, budget::to_string(share_prices[key].value));

    return share_prices[key].value;
}
<|endoftext|>


<commit_before>// Used for testing, do not use it as an example
#include <qpp.h>
#include <experimental/test.h>
// #include <MATLAB/matlab.h>
using namespace qpp;
using std::cout;
using std::endl;

// TODO: circuit description language, load/save from/to file

int main()
{

}
<commit_msg>commit<commit_after>// Used for testing, do not use it as an example
#include <qpp.h>
#include <experimental/test.h>
// #include <MATLAB/matlab.h>
using namespace qpp;
using std::cout;
using std::endl;

// TODO: circuit description language, load/save from/to file
// TODO: measure pure state (full Hilbert space)

int main()
{
    std::cout << disp(gt.T*gt.T) << std::endl;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2000 by Jerry A. Segler, Jr. Based on csFont
    Major improvements by Andrew Zabolotny, <bit@eltech.ru>

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

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdlib.h>
#include "cssysdef.h"
#include "iutil/plugin.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "iutil/objreg.h"
#include "ivaria/reporter.h"
#include "csutil/csvector.h"
#include "fontplex.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_IBASE (csFontServerMultiplexor)
  SCF_IMPLEMENTS_INTERFACE (iFontServer)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csFontServerMultiplexor::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_FACTORY (csFontServerMultiplexor)

SCF_EXPORT_CLASS_TABLE (fontplex)
  SCF_EXPORT_CLASS_DEP (csFontServerMultiplexor,
    "crystalspace.font.server.multiplexor",
    "Crystal Space font server multiplexor",
    "crystalspace.font.server.")
SCF_EXPORT_CLASS_TABLE_END

csFontServerMultiplexor::csFontServerMultiplexor (iBase *pParent)
{
  SCF_CONSTRUCT_IBASE (pParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
}

csFontServerMultiplexor::~csFontServerMultiplexor ()
{
}

bool csFontServerMultiplexor::Initialize (iObjectRegistry *object_reg)
{
  // Query the auxiliary font servers in turn
  char tag [20];
  int idx;
  int errorcount = 0;
  for (idx = 1; ; idx++)
  {
    sprintf (tag, "FontServer.%d", idx);
    csRef<iBase> b (CS_QUERY_REGISTRY_TAG (object_reg, tag));
    if (!b)
    {
      // in cases where just one entry in the server list doesn't work
      // but later ones would those are loaded, too
      errorcount++;
      if (errorcount == 2) break;
    }
    else
    {
      errorcount = 0;
      csRef<iFontServer> fs (SCF_QUERY_INTERFACE (b, iFontServer));
      fs->IncRef ();	// To prevent smart pointer release.
      fontservers.Push (fs);
    }
  }
  if (!fontservers.Length ())
  {
    csReport (object_reg, CS_REPORTER_SEVERITY_WARNING,
        "crystalspace.font.fontplex",
        "Font server multiplexor: WARNING, no slave font servers found!");
  }
  return true;
}

csPtr<iFont> csFontServerMultiplexor::LoadFont (const char *filename)
{
  int i;
  for (i = 0; i < fontservers.Length (); i++)
  {
    csRef<iFont> font (fontservers.Get (i)->LoadFont (filename));
    if (font)
      return csPtr<iFont> (font);
  }
  return NULL;
}

int csFontServerMultiplexor::GetFontCount ()
{
  int i, count = 0;
  for (i = 0; i < fontservers.Length (); i++)
    count += fontservers.Get (i)->GetFontCount ();
  return count;
}

iFont *csFontServerMultiplexor::GetFont (int iIndex)
{
  int i;
  for (i = 0; i < fontservers.Length (); i++)
  {
    int count = fontservers.Get (i)->GetFontCount ();
    if (iIndex < count)
      return fontservers.Get (iIndex)->GetFont (iIndex);
    iIndex -= count;
  }
  return NULL;
}
<commit_msg>fixed fontplex font server (it was looking for FontServer instead of iFontServer in the object registry)<commit_after>/*
    Copyright (C) 2000 by Jerry A. Segler, Jr. Based on csFont
    Major improvements by Andrew Zabolotny, <bit@eltech.ru>

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

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdlib.h>
#include "cssysdef.h"
#include "iutil/plugin.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "iutil/objreg.h"
#include "ivaria/reporter.h"
#include "csutil/csvector.h"
#include "fontplex.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_IBASE (csFontServerMultiplexor)
  SCF_IMPLEMENTS_INTERFACE (iFontServer)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csFontServerMultiplexor::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_FACTORY (csFontServerMultiplexor)

SCF_EXPORT_CLASS_TABLE (fontplex)
  SCF_EXPORT_CLASS_DEP (csFontServerMultiplexor,
    "crystalspace.font.server.multiplexor",
    "Crystal Space font server multiplexor",
    "crystalspace.font.server.")
SCF_EXPORT_CLASS_TABLE_END

csFontServerMultiplexor::csFontServerMultiplexor (iBase *pParent)
{
  SCF_CONSTRUCT_IBASE (pParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
}

csFontServerMultiplexor::~csFontServerMultiplexor ()
{
}

bool csFontServerMultiplexor::Initialize (iObjectRegistry *object_reg)
{
  // Query the auxiliary font servers in turn
  char tag [20];
  int idx;
  int errorcount = 0;
  for (idx = 1; ; idx++)
  {
    sprintf (tag, "iFontServer.%d", idx);
    csRef<iBase> b (CS_QUERY_REGISTRY_TAG (object_reg, tag));
    if (!b)
    {
      // in cases where just one entry in the server list doesn't work
      // but later ones would those are loaded, too
      errorcount++;
      if (errorcount == 2) break;
    }
    else
    {
      errorcount = 0;
      csRef<iFontServer> fs (SCF_QUERY_INTERFACE (b, iFontServer));
      fs->IncRef ();	// To prevent smart pointer release.
      fontservers.Push (fs);
    }
  }
  if (!fontservers.Length ())
  {
    csReport (object_reg, CS_REPORTER_SEVERITY_WARNING,
        "crystalspace.font.fontplex",
        "Font server multiplexor: WARNING, no slave font servers found!");
  }
  return true;
}

csPtr<iFont> csFontServerMultiplexor::LoadFont (const char *filename)
{
  int i;
  for (i = 0; i < fontservers.Length (); i++)
  {
    csRef<iFont> font (fontservers.Get (i)->LoadFont (filename));
    if (font)
      return csPtr<iFont> (font);
  }
  return NULL;
}

int csFontServerMultiplexor::GetFontCount ()
{
  int i, count = 0;
  for (i = 0; i < fontservers.Length (); i++)
    count += fontservers.Get (i)->GetFontCount ();
  return count;
}

iFont *csFontServerMultiplexor::GetFont (int iIndex)
{
  int i;
  for (i = 0; i < fontservers.Length (); i++)
  {
    int count = fontservers.Get (i)->GetFontCount ();
    if (iIndex < count)
      return fontservers.Get (iIndex)->GetFont (iIndex);
    iIndex -= count;
  }
  return NULL;
}
<|endoftext|>


<commit_before>// Used for testing, do not use it as an example
#include <iostream>
#include <fstream>
#include "qpp.h"
#include "experimental/experimental.h"

using namespace qpp;

int main()
{
    std::cout << "Testing...\n";

    std::cout << "Playing with exceptions...\n";
    try
    {
        throw exception::UndefinedType{__FILE__ + std::string(" at line ") +
                                       std::to_string(__LINE__)};
    }
    catch (exception::UndefinedType& e)
    {
        std::cout << e.what() << '\n';
        std::cout << "Exception type: " << e.type_description() << '\n';
    };

    for (idx i = 0; i < 10; ++i)
    {
        std::cout << rand(bigint(0), 10) << " ";
    }
    std::cout << '\n';

    std::ifstream fout("prng_state.txt");
    rdevs.load(fout);
    for (idx i = 0; i < 10; ++i)
    {
        std::cout << rand((bigint) 0, 100) << " ";
    }
}
<commit_msg>commit<commit_after>// Used for testing, do not use it as an example
#include <iostream>
#include <fstream>
#include "qpp.h"
#include "experimental/experimental.h"

using namespace qpp;

int main()
{
    std::cout << "Testing...\n";
}
<|endoftext|>


<commit_before>//===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Parallel.h"
#include "llvm/Config/llvm-config.h"

#include <atomic>
#include <stack>
#include <thread>

using namespace llvm;

namespace {

/// \brief An abstract class that takes closures and runs them asynchronously.
class Executor {
public:
  virtual ~Executor() = default;
  virtual void add(std::function<void()> func) = 0;

  static Executor *getDefaultExecutor();
};

#if !LLVM_ENABLE_THREADS
class SyncExecutor : public Executor {
public:
  virtual void add(std::function<void()> F) { F(); }
};

Executor *Executor::getDefaultExecutor() {
  static SyncExecutor Exec;
  return &Exec;
}

#elif defined(_MSC_VER)
/// \brief An Executor that runs tasks via ConcRT.
class ConcRTExecutor : public Executor {
  struct Taskish {
    Taskish(std::function<void()> Task) : Task(Task) {}

    std::function<void()> Task;

    static void run(void *P) {
      Taskish *Self = static_cast<Taskish *>(P);
      Self->Task();
      concurrency::Free(Self);
    }
  };

public:
  virtual void add(std::function<void()> F) {
    Concurrency::CurrentScheduler::ScheduleTask(
        Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
  }
};

Executor *Executor::getDefaultExecutor() {
  static ConcRTExecutor exec;
  return &exec;
}

#else
/// \brief An implementation of an Executor that runs closures on a thread pool
///   in filo order.
class ThreadPoolExecutor : public Executor {
public:
  explicit ThreadPoolExecutor(
      unsigned ThreadCount = std::thread::hardware_concurrency())
      : Done(ThreadCount) {
    // Spawn all but one of the threads in another thread as spawning threads
    // can take a while.
    std::thread([&, ThreadCount] {
      for (size_t i = 1; i < ThreadCount; ++i) {
        std::thread([=] { work(); }).detach();
      }
      work();
    }).detach();
  }

  ~ThreadPoolExecutor() override {
    std::unique_lock<std::mutex> Lock(Mutex);
    Stop = true;
    Lock.unlock();
    Cond.notify_all();
    // Wait for ~Latch.
  }

  void add(std::function<void()> F) override {
    std::unique_lock<std::mutex> Lock(Mutex);
    WorkStack.push(F);
    Lock.unlock();
    Cond.notify_one();
  }

private:
  void work() {
    while (true) {
      std::unique_lock<std::mutex> Lock(Mutex);
      Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
      if (Stop)
        break;
      auto Task = WorkStack.top();
      WorkStack.pop();
      Lock.unlock();
      Task();
    }
    Done.dec();
  }

  std::atomic<bool> Stop{false};
  std::stack<std::function<void()>> WorkStack;
  std::mutex Mutex;
  std::condition_variable Cond;
  parallel::detail::Latch Done;
};

Executor *Executor::getDefaultExecutor() {
  static ThreadPoolExecutor exec;
  return &exec;
}
#endif
}

void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
  L.inc();
  Executor::getDefaultExecutor()->add([&, F] {
    F();
    L.dec();
  });
}
<commit_msg>Fix -DLLVM_ENABLE_THREADS=OFF build after r302748<commit_after>//===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Parallel.h"
#include "llvm/Config/llvm-config.h"

#include <atomic>
#include <stack>
#include <thread>

using namespace llvm;

namespace {

/// \brief An abstract class that takes closures and runs them asynchronously.
class Executor {
public:
  virtual ~Executor() = default;
  virtual void add(std::function<void()> func) = 0;

  static Executor *getDefaultExecutor();
};

#if !LLVM_ENABLE_THREADS
class SyncExecutor : public Executor {
public:
  virtual void add(std::function<void()> F) { F(); }
};

Executor *Executor::getDefaultExecutor() {
  static SyncExecutor Exec;
  return &Exec;
}

#elif defined(_MSC_VER)
/// \brief An Executor that runs tasks via ConcRT.
class ConcRTExecutor : public Executor {
  struct Taskish {
    Taskish(std::function<void()> Task) : Task(Task) {}

    std::function<void()> Task;

    static void run(void *P) {
      Taskish *Self = static_cast<Taskish *>(P);
      Self->Task();
      concurrency::Free(Self);
    }
  };

public:
  virtual void add(std::function<void()> F) {
    Concurrency::CurrentScheduler::ScheduleTask(
        Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
  }
};

Executor *Executor::getDefaultExecutor() {
  static ConcRTExecutor exec;
  return &exec;
}

#else
/// \brief An implementation of an Executor that runs closures on a thread pool
///   in filo order.
class ThreadPoolExecutor : public Executor {
public:
  explicit ThreadPoolExecutor(
      unsigned ThreadCount = std::thread::hardware_concurrency())
      : Done(ThreadCount) {
    // Spawn all but one of the threads in another thread as spawning threads
    // can take a while.
    std::thread([&, ThreadCount] {
      for (size_t i = 1; i < ThreadCount; ++i) {
        std::thread([=] { work(); }).detach();
      }
      work();
    }).detach();
  }

  ~ThreadPoolExecutor() override {
    std::unique_lock<std::mutex> Lock(Mutex);
    Stop = true;
    Lock.unlock();
    Cond.notify_all();
    // Wait for ~Latch.
  }

  void add(std::function<void()> F) override {
    std::unique_lock<std::mutex> Lock(Mutex);
    WorkStack.push(F);
    Lock.unlock();
    Cond.notify_one();
  }

private:
  void work() {
    while (true) {
      std::unique_lock<std::mutex> Lock(Mutex);
      Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
      if (Stop)
        break;
      auto Task = WorkStack.top();
      WorkStack.pop();
      Lock.unlock();
      Task();
    }
    Done.dec();
  }

  std::atomic<bool> Stop{false};
  std::stack<std::function<void()>> WorkStack;
  std::mutex Mutex;
  std::condition_variable Cond;
  parallel::detail::Latch Done;
};

Executor *Executor::getDefaultExecutor() {
  static ThreadPoolExecutor exec;
  return &exec;
}
#endif
}

#if LLVM_ENABLE_THREADS
void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
  L.inc();
  Executor::getDefaultExecutor()->add([&, F] {
    F();
    L.dec();
  });
}
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_TPL_HPP
#define REALM_COLUMN_TPL_HPP

#include <cstdlib>

#include <realm/util/features.h>
#include <realm/array.hpp>
#include <realm/array_basic.hpp>

namespace realm {

template<class T, class cond> class FloatDoubleNode;
template<class T, class cond> class IntegerNode;
template<class T> class SequentialGetter;

template<class cond, class T> struct ColumnTypeTraits2;

template<class cond> struct ColumnTypeTraits2<cond, int64_t> {
    typedef Column column_type;
    typedef ArrayInteger array_type;
};
template<class cond> struct ColumnTypeTraits2<cond, bool> {
    typedef Column column_type;
    typedef ArrayInteger array_type;
};
template<class cond> struct ColumnTypeTraits2<cond, float> {
    typedef ColumnFloat column_type;
    typedef ArrayFloat array_type;
};
template<class cond> struct ColumnTypeTraits2<cond, double> {
    typedef ColumnDouble column_type;
    typedef ArrayDouble array_type;
};

namespace _impl {
	template <class ColType>
	struct FindInLeaf {
		using LeafType = typename ColType::LeafType;

		template <Action action, class Condition, class T, class R>
		static bool find(const LeafType& leaf, T target, std::size_t local_start, std::size_t local_end, std::size_t leaf_start, QueryState<R>& state)
		{
			Condition cond;
			bool cont = true;
			for(size_t local_index = local_start; cont && local_index < local_end; local_index++) {
				auto v = leaf.get(local_index);
				if(cond(v, target)) {
					cont = state.template match<action, false>(leaf_start + local_index , 0, static_cast<R>(v));
				}
			}
			return cont;
		}
	};

	template <bool Nullable>
	struct FindInLeaf<TColumn<int64_t, Nullable>> {
		using LeafType = typename TColumn<int64_t, Nullable>::LeafType;

		template <Action action, class Condition, class T, class R>
		static bool find(const LeafType& leaf, T target, std::size_t local_start, std::size_t local_end, std::size_t leaf_start, QueryState<R>& state)
		{
			const int c = Condition::condition;
			return leaf.find(c, action, target, local_start, local_end, leaf_start, &state);
		}
	};
}

template <class T, class R, Action action, class Condition, class ColType>
R aggregate(const ColType& column, T target, std::size_t start, std::size_t end,
			std::size_t limit, std::size_t* return_ndx)
{
	using ArrType = typename ColType::LeafType;

	if (end == npos)
		end = column.size();

	QueryState<R> state;
	state.init(action, nullptr, limit);
	SequentialGetter<ColType> sg { &column };

	bool cont = true;
	for (std::size_t s = start; cont && s < end; ) {
		sg.cache_next(s);
		std::size_t start2 = s - sg.m_leaf_start;
		std::size_t end2 = sg.local_end(end);
		cont = _impl::FindInLeaf<ColType>::template find<action, Condition>(*sg.m_leaf_ptr, target, start2, end2, sg.m_leaf_start, state);
		s = sg.m_leaf_start + end2;
	}

	if (return_ndx)
		*return_ndx = state.m_minmax_index;

	return state.m_state;
}

} // namespace realm

#endif // REALM_COLUMN_TPL_HPP
<commit_msg>fixed warning<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_TPL_HPP
#define REALM_COLUMN_TPL_HPP

#include <cstdlib>

#include <realm/util/features.h>
#include <realm/array.hpp>
#include <realm/array_basic.hpp>

namespace realm {

template<class T, class cond> class FloatDoubleNode;
template<class T, class cond> class IntegerNode;
template<class T> class SequentialGetter;

template<class cond, class T> struct ColumnTypeTraits2;

template<class cond> struct ColumnTypeTraits2<cond, int64_t> {
    typedef Column column_type;
    typedef ArrayInteger array_type;
};
template<class cond> struct ColumnTypeTraits2<cond, bool> {
    typedef Column column_type;
    typedef ArrayInteger array_type;
};
template<class cond> struct ColumnTypeTraits2<cond, float> {
    typedef ColumnFloat column_type;
    typedef ArrayFloat array_type;
};
template<class cond> struct ColumnTypeTraits2<cond, double> {
    typedef ColumnDouble column_type;
    typedef ArrayDouble array_type;
};

namespace _impl {
	template <class ColType>
	struct FindInLeaf {
		using LeafType = typename ColType::LeafType;

		template <Action action, class Condition, class T, class R>
		static bool find(const LeafType& leaf, T target, std::size_t local_start, std::size_t local_end, std::size_t leaf_start, QueryState<R>& state)
		{
			Condition cond;
			bool cont = true;
			for(size_t local_index = local_start; cont && local_index < local_end; local_index++) {
				auto v = leaf.get(local_index);
				if(cond(v, target)) {
					cont = state.template match<action, false>(leaf_start + local_index , 0, static_cast<R>(v));
				}
			}
			return cont;
		}
	};

	template <bool Nullable>
	struct FindInLeaf<TColumn<int64_t, Nullable>> {
		using LeafType = typename TColumn<int64_t, Nullable>::LeafType;

		template <Action action, class Condition, class T, class R>
		static bool find(const LeafType& leaf, T target, std::size_t local_start, std::size_t local_end, std::size_t leaf_start, QueryState<R>& state)
		{
			const int c = Condition::condition;
			return leaf.find(c, action, target, local_start, local_end, leaf_start, &state);
		}
	};
}

template <class T, class R, Action action, class Condition, class ColType>
R aggregate(const ColType& column, T target, std::size_t start, std::size_t end,
			std::size_t limit, std::size_t* return_ndx)
{
	if (end == npos)
		end = column.size();

	QueryState<R> state;
	state.init(action, nullptr, limit);
	SequentialGetter<ColType> sg { &column };

	bool cont = true;
	for (std::size_t s = start; cont && s < end; ) {
		sg.cache_next(s);
		std::size_t start2 = s - sg.m_leaf_start;
		std::size_t end2 = sg.local_end(end);
		cont = _impl::FindInLeaf<ColType>::template find<action, Condition>(*sg.m_leaf_ptr, target, start2, end2, sg.m_leaf_start, state);
		s = sg.m_leaf_start + end2;
	}

	if (return_ndx)
		*return_ndx = state.m_minmax_index;

	return state.m_state;
}

} // namespace realm

#endif // REALM_COLUMN_TPL_HPP
<|endoftext|>


<commit_before>#include "VideoTestsApp.h"
#include "ofxXmlSettings.h"
#include "ofGstVideoPlayer.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTime.h"

//--------------------------------------------------------------
void VideoTestsApp::setup(){
	updatingPosition = false;

	//ofSetLogLevel(OF_LOG_VERBOSE);

	ofxXmlSettings xml("settings.xml");
	for(u_int i=0;i<4;i++){
		axisCameras.push_back(new ofxAxisGui());
		axisCameras[i]->setDrawGui(false);
		axisCameras[i]->setAuth(xml.getValue("settings:camera"+ofToString(i+1)+":user",""),xml.getValue("settings:camera"+ofToString(i+1)+":pwd",""));
		axisCameras[i]->setup(xml.getValue("settings:camera"+ofToString(i+1)+":address",""),"Camera"+ofToString(i+1),220,10);
		cvModules.push_back(new ComputerVision);
		ofAddListener(axisCameras[i]->axis->getGstUtils().bufferEvent,cvModules[i],&ComputerVision::newFrame);
	}

	gui.setup("Settings","settings.xml");

	videoParameters.setName("Player");
	videoParameters.add(record.set("record",0,0,axisCameras.size()+1));
	videoParameters.add(usePlayer.set("usePlayer",false));
	videoParameters.add(playerPaused.set("playerPaused",false));
	videoParameters.add(playerPosition.set("playerPosition",0,0,1));
	videoParameters.add(drawCamera.set("drawCamera",axisCameras.size()+1,1,axisCameras.size()+1));
	gui.add(videoParameters);

	ComputerVision::parameters.setName("CV");
	ComputerVision::parameters.add(ComputerVision::thresholdLevel);
	ComputerVision::parameters.add(ComputerVision::showGui);
	ComputerVision::parameters.add(ComputerVision::showImages);
	ComputerVision::parameters.add(ComputerVision::showContours);
	ComputerVision::parameters.add(ComputerVision::minTimeTrigger);
	ComputerVision::parameters.add(ComputerVision::distanceSameTrigger);
	gui.add(ComputerVision::parameters);

	for(u_int i=0;i<axisCameras.size();i++){
		gui.add(&axisCameras[i]->gui);
	}

	gui.getGroup("video").getIntSlider("record").setUpdateOnReleaseOnly(true);
	gui.loadFromFile("settings.xml");
	gui.minimizeAll();

	record.addListener(this,&VideoTestsApp::recordChanged);
	usePlayer.addListener(this,&VideoTestsApp::usePlayerChanged);
	playerPosition.addListener(this,&VideoTestsApp::playerPositionChanged);
	playerPaused.addListener(this,&VideoTestsApp::playerPausedChanged);
	drawCamera.addListener(this,&VideoTestsApp::drawCameraChanged);

	int activeCamera = drawCamera;
	drawCameraChanged(activeCamera);
}

void VideoTestsApp::playerPausedChanged(bool & paused){
	if(usePlayer) player.setPaused(paused);
}

void VideoTestsApp::usePlayerChanged(bool & usePlayer){
	player.close();
	if(usePlayer){
		ofFileDialogResult result = ofSystemLoadDialog("select video",false);
		if(result.bSuccess){
			videoPath=result.filePath;
			player.loadMovie(videoPath);
			player.play();
			ofRemoveListener(axisCameras[0]->axis->getGstUtils().bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofAddListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofAddListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->prerollEvent,cvModules[0],&ComputerVision::newFrame);
		}else{
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->prerollEvent,cvModules[0],&ComputerVision::newFrame);
			ofAddListener(axisCameras[0]->axis->getGstUtils().bufferEvent,cvModules[0],&ComputerVision::newFrame);
			usePlayer = false;
		}
	}else{
		if(player.getPlayer()){
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->prerollEvent,cvModules[0],&ComputerVision::newFrame);
		}
		ofAddListener(axisCameras[0]->axis->getGstUtils().bufferEvent,cvModules[0],&ComputerVision::newFrame);
	}
}

void VideoTestsApp::playerPositionChanged(float & position){
	if(usePlayer && !updatingPosition){
		player.setPosition(position);
	}
}

void VideoTestsApp::recordChanged(int & record){
	if(record){
		string dir = ofGetTimestampString();
		//ofDirectory(dir).create();
		gstRecorder.setup(640,480,24,dir+"0.avi",ofxGstVideoRecorder::YUV,round(axisCameras[0]->axis->fps));
	}else{
		gstRecorder.shutdown();
	}
}

void VideoTestsApp::drawCameraChanged(int & drawCamera){
	if(drawCamera<=(int)cvModules.size()){
		cvModules[drawCamera-1]->setPosition(220,10);
		cvModules[drawCamera-1]->setSize(640,480);
	}else{
		cvModules[0]->setPosition(220,10);
		cvModules[0]->setSize(320,240);
		cvModules[1]->setPosition(550,10);
		cvModules[1]->setSize(320,240);
		cvModules[2]->setPosition(220,260);
		cvModules[2]->setSize(320,240);
		cvModules[3]->setPosition(550,260);
		cvModules[3]->setSize(320,240);
	}
}

//--------------------------------------------------------------
void VideoTestsApp::update(){
	for(u_int i=0;i<axisCameras.size();i++){
		axisCameras[i]->update();
		cvModules[i]->update();
	}
	if(usePlayer){
		player.update();
		updatingPosition = true;
		playerPosition = player.getPosition();
		updatingPosition = false;
	}
	if(record && axisCameras[record-1]->grabber.isFrameNew()){
		gstRecorder.newFrame(axisCameras[record-1]->grabber.getPixelsRef());
	}

}

//--------------------------------------------------------------
void VideoTestsApp::draw(){
	gui.draw();
	drawCameras();
	Poco::LocalDateTime date;
	ofDrawBitmapString(Poco::DateTimeFormatter::format(date,Poco::DateTimeFormat::ASCTIME_FORMAT ),ofGetWidth()-110,20);
	ofDrawBitmapString("app fps: " + ofToString((int)ofGetFrameRate()),ofGetWidth()-110,40);
}

void VideoTestsApp::drawCameras(){
	if(drawCamera<=(int)axisCameras.size()){
		axisCameras[drawCamera-1]->draw(220,10,640,480);
	}else{
		axisCameras[0]->draw(220,10,320,240);
		axisCameras[1]->draw(550,10,320,240);
		axisCameras[2]->draw(220,260,320,240);
		axisCameras[3]->draw(550,260,320,240);
	}
	if(usePlayer){
		if(drawCamera<=(int)axisCameras.size()) player.draw(220,10,640,480);
		else  player.draw(220,10,320,240);
	}
	if(drawCamera<=(int)cvModules.size()){
		cvModules[drawCamera-1]->draw();
	}else{
		for(u_int i=0;i<cvModules.size();i++){
			cvModules[i]->draw();
		}
	}

	/*ofLine(250,ofGetHeight()-30,850,ofGetHeight()-30);
	for(u_int i=0;i<cvModules.size();i++){
		for(u_int j=0;j<cvModules[i]->getTriggers().size();j++){
			ofCircle(ofMap(cvModules[i]->getTriggers()[j],0,1,0.25*i,0.25*(i+1))*600+250,ofGetHeight()-30,3);
		}
	}*/
}

//--------------------------------------------------------------
void VideoTestsApp::keyPressed(int key){
	if(usePlayer && key==OF_KEY_RIGHT){
		player.setFrame(player.getCurrentFrame()+1);
	}
	if(usePlayer && key==OF_KEY_LEFT){
		player.setFrame(player.getCurrentFrame()-1);
	}
	if(usePlayer && key==' '){
		playerPaused = !playerPaused;
	}

}

//--------------------------------------------------------------
void VideoTestsApp::keyReleased(int key){

}

//--------------------------------------------------------------
void VideoTestsApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void VideoTestsApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void VideoTestsApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void VideoTestsApp::mouseReleased(int x, int y, int button){
}

//--------------------------------------------------------------
void VideoTestsApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void VideoTestsApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void VideoTestsApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>correct xml path for user/password and address of camera settings<commit_after>#include "VideoTestsApp.h"
#include "ofxXmlSettings.h"
#include "ofGstVideoPlayer.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTime.h"

//--------------------------------------------------------------
void VideoTestsApp::setup(){
	updatingPosition = false;

	//ofSetLogLevel(OF_LOG_VERBOSE);

	ofxXmlSettings xml("settings.xml");
	for(u_int i=0;i<4;i++){
		axisCameras.push_back(new ofxAxisGui());
		axisCameras[i]->setDrawGui(false);
		axisCameras[i]->setAuth(xml.getValue("Settings:Camera"+ofToString(i+1)+":user",""),xml.getValue("Settings:Camera"+ofToString(i+1)+":pwd",""));
		axisCameras[i]->setup(xml.getValue("Settings:Camera"+ofToString(i+1)+":address",""),"Camera"+ofToString(i+1),220,10);
		cvModules.push_back(new ComputerVision);
		ofAddListener(axisCameras[i]->axis->getGstUtils().bufferEvent,cvModules[i],&ComputerVision::newFrame);
	}

	gui.setup("Settings","settings.xml");

	videoParameters.setName("Player");
	videoParameters.add(record.set("record",0,0,axisCameras.size()+1));
	videoParameters.add(usePlayer.set("usePlayer",false));
	videoParameters.add(playerPaused.set("playerPaused",false));
	videoParameters.add(playerPosition.set("playerPosition",0,0,1));
	videoParameters.add(drawCamera.set("drawCamera",axisCameras.size()+1,1,axisCameras.size()+1));
	gui.add(videoParameters);

	ComputerVision::parameters.setName("CV");
	ComputerVision::parameters.add(ComputerVision::thresholdLevel);
	ComputerVision::parameters.add(ComputerVision::showGui);
	ComputerVision::parameters.add(ComputerVision::showImages);
	ComputerVision::parameters.add(ComputerVision::showContours);
	ComputerVision::parameters.add(ComputerVision::minTimeTrigger);
	ComputerVision::parameters.add(ComputerVision::distanceSameTrigger);
	gui.add(ComputerVision::parameters);

	for(u_int i=0;i<axisCameras.size();i++){
		gui.add(&axisCameras[i]->gui);
	}

	gui.getGroup("video").getIntSlider("record").setUpdateOnReleaseOnly(true);
	gui.loadFromFile("settings.xml");
	gui.minimizeAll();

	record.addListener(this,&VideoTestsApp::recordChanged);
	usePlayer.addListener(this,&VideoTestsApp::usePlayerChanged);
	playerPosition.addListener(this,&VideoTestsApp::playerPositionChanged);
	playerPaused.addListener(this,&VideoTestsApp::playerPausedChanged);
	drawCamera.addListener(this,&VideoTestsApp::drawCameraChanged);

	int activeCamera = drawCamera;
	drawCameraChanged(activeCamera);
}

void VideoTestsApp::playerPausedChanged(bool & paused){
	if(usePlayer) player.setPaused(paused);
}

void VideoTestsApp::usePlayerChanged(bool & usePlayer){
	player.close();
	if(usePlayer){
		ofFileDialogResult result = ofSystemLoadDialog("select video",false);
		if(result.bSuccess){
			videoPath=result.filePath;
			player.loadMovie(videoPath);
			player.play();
			ofRemoveListener(axisCameras[0]->axis->getGstUtils().bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofAddListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofAddListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->prerollEvent,cvModules[0],&ComputerVision::newFrame);
		}else{
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->prerollEvent,cvModules[0],&ComputerVision::newFrame);
			ofAddListener(axisCameras[0]->axis->getGstUtils().bufferEvent,cvModules[0],&ComputerVision::newFrame);
			usePlayer = false;
		}
	}else{
		if(player.getPlayer()){
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->bufferEvent,cvModules[0],&ComputerVision::newFrame);
			ofRemoveListener(((ofGstVideoPlayer*)player.getPlayer().get())->getGstVideoUtils()->prerollEvent,cvModules[0],&ComputerVision::newFrame);
		}
		ofAddListener(axisCameras[0]->axis->getGstUtils().bufferEvent,cvModules[0],&ComputerVision::newFrame);
	}
}

void VideoTestsApp::playerPositionChanged(float & position){
	if(usePlayer && !updatingPosition){
		player.setPosition(position);
	}
}

void VideoTestsApp::recordChanged(int & record){
	if(record){
		string dir = ofGetTimestampString();
		//ofDirectory(dir).create();
		gstRecorder.setup(640,480,24,dir+"0.avi",ofxGstVideoRecorder::YUV,round(axisCameras[0]->axis->fps));
	}else{
		gstRecorder.shutdown();
	}
}

void VideoTestsApp::drawCameraChanged(int & drawCamera){
	if(drawCamera<=(int)cvModules.size()){
		cvModules[drawCamera-1]->setPosition(220,10);
		cvModules[drawCamera-1]->setSize(640,480);
	}else{
		cvModules[0]->setPosition(220,10);
		cvModules[0]->setSize(320,240);
		cvModules[1]->setPosition(550,10);
		cvModules[1]->setSize(320,240);
		cvModules[2]->setPosition(220,260);
		cvModules[2]->setSize(320,240);
		cvModules[3]->setPosition(550,260);
		cvModules[3]->setSize(320,240);
	}
}

//--------------------------------------------------------------
void VideoTestsApp::update(){
	for(u_int i=0;i<axisCameras.size();i++){
		axisCameras[i]->update();
		cvModules[i]->update();
	}
	if(usePlayer){
		player.update();
		updatingPosition = true;
		playerPosition = player.getPosition();
		updatingPosition = false;
	}
	if(record && axisCameras[record-1]->grabber.isFrameNew()){
		gstRecorder.newFrame(axisCameras[record-1]->grabber.getPixelsRef());
	}

}

//--------------------------------------------------------------
void VideoTestsApp::draw(){
	gui.draw();
	drawCameras();
	Poco::LocalDateTime date;
	ofDrawBitmapString(Poco::DateTimeFormatter::format(date,Poco::DateTimeFormat::ASCTIME_FORMAT ),ofGetWidth()-110,20);
	ofDrawBitmapString("app fps: " + ofToString((int)ofGetFrameRate()),ofGetWidth()-110,40);
}

void VideoTestsApp::drawCameras(){
	if(drawCamera<=(int)axisCameras.size()){
		axisCameras[drawCamera-1]->draw(220,10,640,480);
	}else{
		axisCameras[0]->draw(220,10,320,240);
		axisCameras[1]->draw(550,10,320,240);
		axisCameras[2]->draw(220,260,320,240);
		axisCameras[3]->draw(550,260,320,240);
	}
	if(usePlayer){
		if(drawCamera<=(int)axisCameras.size()) player.draw(220,10,640,480);
		else  player.draw(220,10,320,240);
	}
	if(drawCamera<=(int)cvModules.size()){
		cvModules[drawCamera-1]->draw();
	}else{
		for(u_int i=0;i<cvModules.size();i++){
			cvModules[i]->draw();
		}
	}

	/*ofLine(250,ofGetHeight()-30,850,ofGetHeight()-30);
	for(u_int i=0;i<cvModules.size();i++){
		for(u_int j=0;j<cvModules[i]->getTriggers().size();j++){
			ofCircle(ofMap(cvModules[i]->getTriggers()[j],0,1,0.25*i,0.25*(i+1))*600+250,ofGetHeight()-30,3);
		}
	}*/
}

//--------------------------------------------------------------
void VideoTestsApp::keyPressed(int key){
	if(usePlayer && key==OF_KEY_RIGHT){
		player.setFrame(player.getCurrentFrame()+1);
	}
	if(usePlayer && key==OF_KEY_LEFT){
		player.setFrame(player.getCurrentFrame()-1);
	}
	if(usePlayer && key==' '){
		playerPaused = !playerPaused;
	}

}

//--------------------------------------------------------------
void VideoTestsApp::keyReleased(int key){

}

//--------------------------------------------------------------
void VideoTestsApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void VideoTestsApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void VideoTestsApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void VideoTestsApp::mouseReleased(int x, int y, int button){
}

//--------------------------------------------------------------
void VideoTestsApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void VideoTestsApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void VideoTestsApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>