<commit_before>/** \file   rss_subset_aggregator.cc
 *  \brief  Aggregates RSS feeds.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2021 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero 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, see <http://www.gnu.org/licenses/>.
 */
#include <algorithm>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <cinttypes>
#include <cstring>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "EmailSender.h"
#include "FileUtil.h"
#include "HtmlUtil.h"
#include "SqlUtil.h"
#include "StringUtil.h"
#include "SyndicationFormat.h"
#include "Template.h"
#include "UBTools.h"
#include "util.h"
#include "VuFind.h"
#include "XmlWriter.h"

namespace {

[[noreturn]] void Usage() {
    ::Usage("--mode=(email|rss_xml) (user_id|error_email_address) subsystem_type]\n"
            "If the mode is \"rss_xml\" a VuFind user_id needs to be specified, o/w an error email address should be provided.");
}

struct HarvestedRSSItem {
    SyndicationFormat::Item item_;
    std::string feed_title_;
    std::string feed_url_;

    HarvestedRSSItem(const SyndicationFormat::Item item, const std::string feed_title, const std::string feed_url)
        : item_(item), feed_title_(feed_title), feed_url_(feed_url) {}
};

struct ChannelDesc {
    std::string title_;
    std::string link_;
public:
    ChannelDesc(const std::string &title, const std::string &link)
        : title_(title), link_(link) { }
};

const std::map<std::string, ChannelDesc> subsystem_type_to_channel_desc_map = {
    { "relbib",  ChannelDesc("RelBib RSS Aggregator",  "https://relbib.de/")                },
    { "ixtheo",  ChannelDesc("IxTheo RSS Aggregator",  "https://itheo.de/")                 },
    { "krimdok", ChannelDesc("KrimDok RSS Aggregator", "https://krimdok.uni-tuebingen.de/") },
};

std::string GetChannelDescEntry(const std::string &subsystem_type, const std::string &entry) {
    const auto subsystem_type_and_channel_desc(subsystem_type_to_channel_desc_map.find(subsystem_type));
    if (subsystem_type_and_channel_desc == subsystem_type_to_channel_desc_map.cend())
        LOG_ERROR("unknown subsystem type \"" + subsystem_type + "\"!");

    if (entry == "title")
        return subsystem_type_and_channel_desc->second.title_;
    if (entry == "link")
        return subsystem_type_and_channel_desc->second.link_;
    LOG_ERROR("unknown entry name \"" + entry + "\"!");
}

void WriteRSSFeedXMLOutput(const std::string &subsystem_type, const std::vector<HarvestedRSSItem> &harvested_items,
                           XmlWriter * const xml_writer)
{
    xml_writer->openTag("rss", { { "version", "2.0" } });
    xml_writer->openTag("channel");
    xml_writer->writeTagsWithData("title", GetChannelDescEntry(subsystem_type, "title"));
    xml_writer->writeTagsWithData("link", GetChannelDescEntry(subsystem_type, "link"));
    xml_writer->writeTagsWithData("description", "RSS Aggregator");

    for (const auto &harvested_item : harvested_items) {
        xml_writer->openTag("item");

        const auto title(harvested_item.item_.getTitle());
        if (not title.empty())
            xml_writer->writeTagsWithData("title", harvested_item.item_.getTitle());

        xml_writer->writeTagsWithData("link", harvested_item.item_.getLink());

        const auto description(HtmlUtil::ShortenText(harvested_item.item_.getDescription(), /*max_length = */500));
        if (not description.empty())
            xml_writer->writeTagsWithData("description", description);

        xml_writer->writeTagsWithData("pubDate",
                                      TimeUtil::TimeTToString(harvested_item.item_.getPubDate(), TimeUtil::RFC822_FORMAT,
                                                                     TimeUtil::UTC));
        xml_writer->writeTagsWithData("guid", harvested_item.item_.getId());
        xml_writer->closeTag("item", /* suppress_indent */ false);
    }

    xml_writer->closeTag("channel");
    xml_writer->closeTag("rss");
}

struct FeedNameAndURL {
    std::string name_;
    std::string url_;
public:
    FeedNameAndURL() = default;
    FeedNameAndURL(const FeedNameAndURL &other) = default;
    FeedNameAndURL(const std::string &name, const std::string &url)
        : name_(name), url_(url) { }
};

// \return True if a notification email was sent successfully, o/w false.
bool SendEmail(const std::string &subsystem_type, const std::string &email_sender, const std::string &user_email,
               const std::string &user_address, const std::string &language,
               const std::vector<HarvestedRSSItem> &harvested_items)
{
    const auto template_filename_prefix(UBTools::GetTuelibPath() + "rss_email.template");
    std::string template_filename(template_filename_prefix + "." + language);
    if (not FileUtil::Exists(template_filename))
        template_filename = template_filename_prefix + ".en";
    static const std::string email_template(FileUtil::ReadStringOrDie(template_filename));

    Template::Map names_to_values_map;
    names_to_values_map.insertScalar("user_email", user_email);
    names_to_values_map.insertScalar("user_address", user_address);

    std::vector<std::string> titles, links, descriptions;
    for (const auto &harvested_item : harvested_items) {
        titles.emplace_back(HtmlUtil::HtmlEscape(harvested_item.item_.getTitle()));
        links.emplace_back(harvested_item.item_.getLink());
        descriptions.emplace_back(HtmlUtil::HtmlEscape(harvested_item.item_.getDescription()));
    }
    names_to_values_map.insertArray("titles", titles);
    names_to_values_map.insertArray("links", links);
    names_to_values_map.insertArray("descriptions", descriptions);

    const auto email_body(Template::ExpandTemplate(email_template, names_to_values_map));
    const auto retcode(EmailSender::SimplerSendEmail(email_sender, { user_email }, GetChannelDescEntry(subsystem_type, "title"),
                                                     email_body, EmailSender::DO_NOT_SET_PRIORITY, EmailSender::HTML));
    if (retcode <= 299)
        return true;

    LOG_WARNING("EmailSender::SimplerSendEmail returned " + std::to_string(retcode) + " while trying to send to \""
                + user_email + "\"!");
    return false;
}

const unsigned DEFAULT_XML_INDENT_AMOUNT(2);

void GenerateFeed(const std::string &subsystem_type, const std::vector<HarvestedRSSItem> &harvested_items) {
    XmlWriter xml_writer(FileUtil::OpenOutputFileOrDie("/dev/stdout").release(),
                         XmlWriter::WriteTheXmlDeclaration, DEFAULT_XML_INDENT_AMOUNT);
    WriteRSSFeedXMLOutput(subsystem_type, harvested_items, &xml_writer);
}

bool ProcessFeeds(const std::string &user_id, const std::string &rss_feed_last_notification, const std::string &email_sender,
                  const std::string &user_email, const std::string &user_address, const std::string &language,
                  const bool send_email, const std::string &subsystem_type,
                  DbConnection * const db_connection)
{
    db_connection->queryOrDie("SELECT rss_feeds_id FROM tuefind_rss_subscriptions WHERE user_id=" + user_id);
    auto rss_subscriptions_result_set(db_connection->getLastResultSet());
    std::vector<std::string> feed_ids;
    while (const auto row = rss_subscriptions_result_set.getNextRow())\
        feed_ids.emplace_back(row["rss_feeds_id"]);
    if (feed_ids.empty())
        return false;

    std::vector<HarvestedRSSItem> harvested_items;
    std::string max_insertion_time;
    for (const auto &feed_id : feed_ids) {
        db_connection->queryOrDie("SELECT feed_name,feed_url FROM tuefind_rss_feeds WHERE id=" + feed_id);
        auto feed_result_set(db_connection->getLastResultSet());
        const auto feed_row(feed_result_set.getNextRow());
        const auto feed_name(feed_row["feed_name"]);
        const auto feed_url(feed_row["feed_url"]);
        feed_result_set.~DbResultSet();

        db_connection->queryOrDie("SELECT item_title,item_description,item_url,item_id,pub_date,insertion_time FROM "
                                  "tuefind_rss_items WHERE rss_feeds_id=" + feed_id + " AND insertion_time > '"
                                  + rss_feed_last_notification + "'");
        auto items_result_set(db_connection->getLastResultSet());
        while (const auto item_row = items_result_set.getNextRow()) {
            harvested_items.emplace_back(SyndicationFormat::Item(item_row["item_title"], item_row["item_description"],
                                                                 item_row["item_url"], item_row["item_id"],
                                                                 SqlUtil::DatetimeToTimeT(item_row["pub_date"])),
                                         feed_name, feed_url);
            const auto insertion_time(item_row["insertion_time"]);
            if (insertion_time > max_insertion_time)
                max_insertion_time = insertion_time;
        }
    }
    if (harvested_items.empty())
        return false;

    if (send_email) {
        if (not SendEmail(subsystem_type, email_sender, user_email, user_address, language, harvested_items))
            return true;
        db_connection->queryOrDie("INSERT INTO user SET tuefind_rss_feed_last_notification='" + max_insertion_time
                                  + "' WHERE id=" + user_id);
    } else
        GenerateFeed(subsystem_type, harvested_items);
    return true;
}

// Yes, this function has a confusing name but I could not think of a better one. :-(
// What is meant is how to address a user!
std::string GenerateUserAddress(const std::string &first_name, const std::string &last_name) {
    if (last_name.empty())
        return first_name;

    return first_name + " " + last_name;
}

} // unnamed namespace

struct UserInfo {
    std::string user_id_;
    std::string first_name_;
    std::string last_name_;
    std::string email_;
    std::string rss_feed_last_notification_;
public:
    UserInfo() = default;
    UserInfo(const UserInfo &other) = default;
    UserInfo(const std::string &user_id, const std::string &first_name, const std::string &last_name,
             const std::string &email, const std::string &rss_feed_last_notification)
        : user_id_(user_id), first_name_(first_name), last_name_(last_name), email_(email),
          rss_feed_last_notification_(rss_feed_last_notification) { }
};

int Main(int argc, char *argv[]) {
    if (argc != 4)
        Usage();

    std::string error_email_address, vufind_user_id;
    if (std::strcmp(argv[1], "--mode=email") == 0)
        vufind_user_id = argv[2];
    else if (std::strcmp(argv[1], "--mode=rss_xml") == 0)
        vufind_user_id = argv[2];
    else
        Usage();
    const std::string subsystem_type(argv[3]);
    if (subsystem_type != "ixtheo" and subsystem_type != "relbib" and subsystem_type != "krimdok")
        LOG_ERROR("subsystem_type must be one of {ixtheo,relbib,krimdok}!");

    const auto db_connection(VuFind::GetDbConnection());

    std::string sql_query("SELECT id,firstname,lastname,email,tuefind_rss_feed_send_emails"
                          ",tuefind_rss_feed_last_notification FROM user");
    if (vufind_user_id.empty())
        sql_query += " WHERE tuefind_rss_feed_send_emails IS TRUE";
    else
        sql_query += " WHERE id=" + db_connection->escapeAndQuoteString(vufind_user_id);
    db_connection->queryOrDie(sql_query);

    auto user_result_set(db_connection->getLastResultSet());
    std::unordered_map<std::string, UserInfo> ids_to_user_infos_map;
    while (const auto user_row = user_result_set.getNextRow())
        ids_to_user_infos_map[user_row["id"]] =
            UserInfo(user_row["id"], user_row["firstname"], user_row["lastname"], user_row["email"],
                     user_row["tuefind_rss_feed_last_notification"]);

    unsigned feed_generation_count(0), email_sent_count(0);
    for (const auto &[user_id, user_info] : ids_to_user_infos_map) {
        if (vufind_user_id.empty() and not EmailSender::IsValidEmailAddress(user_info.email_)) {
            LOG_WARNING("no valid email address for vufind.user.id " + user_id + "!");
            continue;
        }

        const std::string language("en");
        if (ProcessFeeds(user_id, user_info.rss_feed_last_notification_, error_email_address, user_info.email_,
                         GenerateUserAddress(user_info.first_name_, user_info.last_name_),
                         language, vufind_user_id.empty(), subsystem_type, db_connection.get()))
        {
            if (vufind_user_id.empty())
                ++email_sent_count;
            ++feed_generation_count;
        }
    }
    LOG_INFO("Generated " + std::to_string(feed_generation_count) + " RSS feed(s) and sent "
             + std::to_string(email_sent_count) + " email(s).");

    return EXIT_SUCCESS;
}
<commit_msg>Fixed an obvious bug.<commit_after>/** \file   rss_subset_aggregator.cc
 *  \brief  Aggregates RSS feeds.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2021 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero 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, see <http://www.gnu.org/licenses/>.
 */
#include <algorithm>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <cinttypes>
#include <cstring>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "EmailSender.h"
#include "FileUtil.h"
#include "HtmlUtil.h"
#include "SqlUtil.h"
#include "StringUtil.h"
#include "SyndicationFormat.h"
#include "Template.h"
#include "UBTools.h"
#include "util.h"
#include "VuFind.h"
#include "XmlWriter.h"

namespace {

[[noreturn]] void Usage() {
    ::Usage("--mode=(email|rss_xml) (user_id|error_email_address) subsystem_type]\n"
            "If the mode is \"rss_xml\" a VuFind user_id needs to be specified, o/w an error email address should be provided.");
}

struct HarvestedRSSItem {
    SyndicationFormat::Item item_;
    std::string feed_title_;
    std::string feed_url_;

    HarvestedRSSItem(const SyndicationFormat::Item item, const std::string feed_title, const std::string feed_url)
        : item_(item), feed_title_(feed_title), feed_url_(feed_url) {}
};

struct ChannelDesc {
    std::string title_;
    std::string link_;
public:
    ChannelDesc(const std::string &title, const std::string &link)
        : title_(title), link_(link) { }
};

const std::map<std::string, ChannelDesc> subsystem_type_to_channel_desc_map = {
    { "relbib",  ChannelDesc("RelBib RSS Aggregator",  "https://relbib.de/")                },
    { "ixtheo",  ChannelDesc("IxTheo RSS Aggregator",  "https://itheo.de/")                 },
    { "krimdok", ChannelDesc("KrimDok RSS Aggregator", "https://krimdok.uni-tuebingen.de/") },
};

std::string GetChannelDescEntry(const std::string &subsystem_type, const std::string &entry) {
    const auto subsystem_type_and_channel_desc(subsystem_type_to_channel_desc_map.find(subsystem_type));
    if (subsystem_type_and_channel_desc == subsystem_type_to_channel_desc_map.cend())
        LOG_ERROR("unknown subsystem type \"" + subsystem_type + "\"!");

    if (entry == "title")
        return subsystem_type_and_channel_desc->second.title_;
    if (entry == "link")
        return subsystem_type_and_channel_desc->second.link_;
    LOG_ERROR("unknown entry name \"" + entry + "\"!");
}

void WriteRSSFeedXMLOutput(const std::string &subsystem_type, const std::vector<HarvestedRSSItem> &harvested_items,
                           XmlWriter * const xml_writer)
{
    xml_writer->openTag("rss", { { "version", "2.0" } });
    xml_writer->openTag("channel");
    xml_writer->writeTagsWithData("title", GetChannelDescEntry(subsystem_type, "title"));
    xml_writer->writeTagsWithData("link", GetChannelDescEntry(subsystem_type, "link"));
    xml_writer->writeTagsWithData("description", "RSS Aggregator");

    for (const auto &harvested_item : harvested_items) {
        xml_writer->openTag("item");

        const auto title(harvested_item.item_.getTitle());
        if (not title.empty())
            xml_writer->writeTagsWithData("title", harvested_item.item_.getTitle());

        xml_writer->writeTagsWithData("link", harvested_item.item_.getLink());

        const auto description(HtmlUtil::ShortenText(harvested_item.item_.getDescription(), /*max_length = */500));
        if (not description.empty())
            xml_writer->writeTagsWithData("description", description);

        xml_writer->writeTagsWithData("pubDate",
                                      TimeUtil::TimeTToString(harvested_item.item_.getPubDate(), TimeUtil::RFC822_FORMAT,
                                                                     TimeUtil::UTC));
        xml_writer->writeTagsWithData("guid", harvested_item.item_.getId());
        xml_writer->closeTag("item", /* suppress_indent */ false);
    }

    xml_writer->closeTag("channel");
    xml_writer->closeTag("rss");
}

struct FeedNameAndURL {
    std::string name_;
    std::string url_;
public:
    FeedNameAndURL() = default;
    FeedNameAndURL(const FeedNameAndURL &other) = default;
    FeedNameAndURL(const std::string &name, const std::string &url)
        : name_(name), url_(url) { }
};

// \return True if a notification email was sent successfully, o/w false.
bool SendEmail(const std::string &subsystem_type, const std::string &email_sender, const std::string &user_email,
               const std::string &user_address, const std::string &language,
               const std::vector<HarvestedRSSItem> &harvested_items)
{
    const auto template_filename_prefix(UBTools::GetTuelibPath() + "rss_email.template");
    std::string template_filename(template_filename_prefix + "." + language);
    if (not FileUtil::Exists(template_filename))
        template_filename = template_filename_prefix + ".en";
    static const std::string email_template(FileUtil::ReadStringOrDie(template_filename));

    Template::Map names_to_values_map;
    names_to_values_map.insertScalar("user_email", user_email);
    names_to_values_map.insertScalar("user_address", user_address);

    std::vector<std::string> titles, links, descriptions;
    for (const auto &harvested_item : harvested_items) {
        titles.emplace_back(HtmlUtil::HtmlEscape(harvested_item.item_.getTitle()));
        links.emplace_back(harvested_item.item_.getLink());
        descriptions.emplace_back(HtmlUtil::HtmlEscape(harvested_item.item_.getDescription()));
    }
    names_to_values_map.insertArray("titles", titles);
    names_to_values_map.insertArray("links", links);
    names_to_values_map.insertArray("descriptions", descriptions);

    const auto email_body(Template::ExpandTemplate(email_template, names_to_values_map));
    const auto retcode(EmailSender::SimplerSendEmail(email_sender, { user_email }, GetChannelDescEntry(subsystem_type, "title"),
                                                     email_body, EmailSender::DO_NOT_SET_PRIORITY, EmailSender::HTML));
    if (retcode <= 299)
        return true;

    LOG_WARNING("EmailSender::SimplerSendEmail returned " + std::to_string(retcode) + " while trying to send to \""
                + user_email + "\"!");
    return false;
}

const unsigned DEFAULT_XML_INDENT_AMOUNT(2);

void GenerateFeed(const std::string &subsystem_type, const std::vector<HarvestedRSSItem> &harvested_items) {
    XmlWriter xml_writer(FileUtil::OpenOutputFileOrDie("/dev/stdout").release(),
                         XmlWriter::WriteTheXmlDeclaration, DEFAULT_XML_INDENT_AMOUNT);
    WriteRSSFeedXMLOutput(subsystem_type, harvested_items, &xml_writer);
}

bool ProcessFeeds(const std::string &user_id, const std::string &rss_feed_last_notification, const std::string &email_sender,
                  const std::string &user_email, const std::string &user_address, const std::string &language,
                  const bool send_email, const std::string &subsystem_type,
                  DbConnection * const db_connection)
{
    db_connection->queryOrDie("SELECT rss_feeds_id FROM tuefind_rss_subscriptions WHERE user_id=" + user_id);
    auto rss_subscriptions_result_set(db_connection->getLastResultSet());
    std::vector<std::string> feed_ids;
    while (const auto row = rss_subscriptions_result_set.getNextRow())\
        feed_ids.emplace_back(row["rss_feeds_id"]);
    if (feed_ids.empty())
        return false;

    std::vector<HarvestedRSSItem> harvested_items;
    std::string max_insertion_time;
    for (const auto &feed_id : feed_ids) {
        db_connection->queryOrDie("SELECT feed_name,feed_url FROM tuefind_rss_feeds WHERE id=" + feed_id);
        auto feed_result_set(db_connection->getLastResultSet());
        const auto feed_row(feed_result_set.getNextRow());
        const auto feed_name(feed_row["feed_name"]);
        const auto feed_url(feed_row["feed_url"]);
        feed_result_set.~DbResultSet();

        db_connection->queryOrDie("SELECT item_title,item_description,item_url,item_id,pub_date,insertion_time FROM "
                                  "tuefind_rss_items WHERE rss_feeds_id=" + feed_id + " AND insertion_time > '"
                                  + rss_feed_last_notification + "'");
        auto items_result_set(db_connection->getLastResultSet());
        while (const auto item_row = items_result_set.getNextRow()) {
            harvested_items.emplace_back(SyndicationFormat::Item(item_row["item_title"], item_row["item_description"],
                                                                 item_row["item_url"], item_row["item_id"],
                                                                 SqlUtil::DatetimeToTimeT(item_row["pub_date"])),
                                         feed_name, feed_url);
            const auto insertion_time(item_row["insertion_time"]);
            if (insertion_time > max_insertion_time)
                max_insertion_time = insertion_time;
        }
    }
    if (harvested_items.empty())
        return false;

    if (send_email) {
        if (not SendEmail(subsystem_type, email_sender, user_email, user_address, language, harvested_items))
            return true;
        db_connection->queryOrDie("UPDATE user SET tuefind_rss_feed_last_notification='" + max_insertion_time
                                  + "' WHERE id=" + user_id);
    } else
        GenerateFeed(subsystem_type, harvested_items);
    return true;
}

// Yes, this function has a confusing name but I could not think of a better one. :-(
// What is meant is how to address a user!
std::string GenerateUserAddress(const std::string &first_name, const std::string &last_name) {
    if (last_name.empty())
        return first_name;

    return first_name + " " + last_name;
}

} // unnamed namespace

struct UserInfo {
    std::string user_id_;
    std::string first_name_;
    std::string last_name_;
    std::string email_;
    std::string rss_feed_last_notification_;
public:
    UserInfo() = default;
    UserInfo(const UserInfo &other) = default;
    UserInfo(const std::string &user_id, const std::string &first_name, const std::string &last_name,
             const std::string &email, const std::string &rss_feed_last_notification)
        : user_id_(user_id), first_name_(first_name), last_name_(last_name), email_(email),
          rss_feed_last_notification_(rss_feed_last_notification) { }
};

int Main(int argc, char *argv[]) {
    if (argc != 4)
        Usage();

    std::string error_email_address, vufind_user_id;
    if (std::strcmp(argv[1], "--mode=email") == 0)
        vufind_user_id = argv[2];
    else if (std::strcmp(argv[1], "--mode=rss_xml") == 0)
        vufind_user_id = argv[2];
    else
        Usage();
    const std::string subsystem_type(argv[3]);
    if (subsystem_type != "ixtheo" and subsystem_type != "relbib" and subsystem_type != "krimdok")
        LOG_ERROR("subsystem_type must be one of {ixtheo,relbib,krimdok}!");

    const auto db_connection(VuFind::GetDbConnection());

    std::string sql_query("SELECT id,firstname,lastname,email,tuefind_rss_feed_send_emails"
                          ",tuefind_rss_feed_last_notification FROM user");
    if (vufind_user_id.empty())
        sql_query += " WHERE tuefind_rss_feed_send_emails IS TRUE";
    else
        sql_query += " WHERE id=" + db_connection->escapeAndQuoteString(vufind_user_id);
    db_connection->queryOrDie(sql_query);

    auto user_result_set(db_connection->getLastResultSet());
    std::unordered_map<std::string, UserInfo> ids_to_user_infos_map;
    while (const auto user_row = user_result_set.getNextRow())
        ids_to_user_infos_map[user_row["id"]] =
            UserInfo(user_row["id"], user_row["firstname"], user_row["lastname"], user_row["email"],
                     user_row["tuefind_rss_feed_last_notification"]);

    unsigned feed_generation_count(0), email_sent_count(0);
    for (const auto &[user_id, user_info] : ids_to_user_infos_map) {
        if (vufind_user_id.empty() and not EmailSender::IsValidEmailAddress(user_info.email_)) {
            LOG_WARNING("no valid email address for vufind.user.id " + user_id + "!");
            continue;
        }

        const std::string language("en");
        if (ProcessFeeds(user_id, user_info.rss_feed_last_notification_, error_email_address, user_info.email_,
                         GenerateUserAddress(user_info.first_name_, user_info.last_name_),
                         language, vufind_user_id.empty(), subsystem_type, db_connection.get()))
        {
            if (vufind_user_id.empty())
                ++email_sent_count;
            ++feed_generation_count;
        }
    }
    LOG_INFO("Generated " + std::to_string(feed_generation_count) + " RSS feed(s) and sent "
             + std::to_string(email_sent_count) + " email(s).");

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/common/vsync_waiter.h"

#include "flutter/fml/task_runner.h"
#include "flutter/fml/trace_event.h"

namespace shell {

VsyncWaiter::VsyncWaiter(blink::TaskRunners task_runners)
    : task_runners_(std::move(task_runners)) {}

VsyncWaiter::~VsyncWaiter() = default;

void VsyncWaiter::AsyncWaitForVsync(Callback callback) {
  {
    std::lock_guard<std::mutex> lock(callback_mutex_);
    callback_ = std::move(callback);
  }
  AwaitVSync();
}

void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
                               fml::TimePoint frame_target_time) {
  Callback callback;

  {
    std::lock_guard<std::mutex> lock(callback_mutex_);
    callback = std::move(callback_);
  }

  if (!callback) {
    return;
  }

  task_runners_.GetUITaskRunner()->PostTask(
      [callback, frame_start_time, frame_target_time]() {
        // Note: The tag name must be "VSYNC" (it is special) so that the
        // "Highlight
        // Vsync" checkbox in the timeline can be enabled.
        TRACE_EVENT0("flutter", "VSYNC");
        callback(frame_start_time, frame_target_time);
      });
}

}  // namespace shell
<commit_msg>Remove the "VSYNC" trace event on Fuchsia (#5907)<commit_after>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/common/vsync_waiter.h"

#include "flutter/fml/task_runner.h"
#include "flutter/fml/trace_event.h"

namespace shell {

VsyncWaiter::VsyncWaiter(blink::TaskRunners task_runners)
    : task_runners_(std::move(task_runners)) {}

VsyncWaiter::~VsyncWaiter() = default;

void VsyncWaiter::AsyncWaitForVsync(Callback callback) {
  {
    std::lock_guard<std::mutex> lock(callback_mutex_);
    callback_ = std::move(callback);
  }
  AwaitVSync();
}

void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
                               fml::TimePoint frame_target_time) {
  Callback callback;

  {
    std::lock_guard<std::mutex> lock(callback_mutex_);
    callback = std::move(callback_);
  }

  if (!callback) {
    return;
  }

  task_runners_.GetUITaskRunner()->PostTask(
      [callback, frame_start_time, frame_target_time]() {
#if defined(OS_FUCHSIA)
        // In general, traces on Fuchsia are recorded across the whole system.
        // Because of this, emitting a "VSYNC" event per flutter process is
        // undesirable, as the events will collide with each other.  We
        // instead let another area of the system emit them.
        TRACE_EVENT0("flutter", "vsync callback");
#else
        // Note: The tag name must be "VSYNC" (it is special) so that the
        // "Highlight Vsync" checkbox in the timeline can be enabled.
        TRACE_EVENT0("flutter", "VSYNC");
#endif
        callback(frame_start_time, frame_target_time);
      });
}

}  // namespace shell
<|endoftext|>


<commit_before>#include "video.h"

#include "SDL_render.h"

#include "debug.h"

void capture_application_target() {
    SDL_GL_BindTexture ( shim.target, nullptr, nullptr );
    libshimmer->capture_application_texture();
}

void set_application_render_target() {
    if ( shim.target ) {
        SDL_DestroyTexture ( shim.target );
    }

    int w, h;

    SDL_GetWindowSize ( shim.window, &w, &h );

    shim.target = SDL_CreateTexture ( shim.renderer,
                                      SDL_PIXELFORMAT_BGRA32,
                                      SDL_TEXTUREACCESS_TARGET,
                                      w, h );

    if ( SDL_SetRenderTarget ( shim.renderer, shim.target ) != 0 ) {
        std::cout << "Could not set render target: "
                  << SDL_GetError() << std::endl;

        std::cout << glpp::gl_framebuffer_status_to_string (
            glpp::framebuffer::check_status() ) << "\n";
    }

    capture_application_target();
}

void init_shimmer() {
    if ( !shim.opengl_initiliased ) {
        glewExperimental = GL_TRUE;

        GLenum glew_err = glewInit();

        if ( glew_err ) {
            std::cerr << "Error) Unable to initialise GLEW: "
                      << glewGetErrorString ( glew_err ) << std::endl;
        }

        shim.opengl_initiliased = true;
    }

    libshimmer->init_renderer();
}

SDL_Window* SDL_CreateWindow ( const char* title,
                               int         x,
                               int         y,
                               int         w,
                               int         h,
                               Uint32      flags ) {
    SHIM_LOG ( 2 );

    std::string wtitle = title;
    glpp::coords_2i coords ( x, y );
    glpp::dims_2u   dims ( w, h );
    libshimmer->create_window ( wtitle, coords, dims );

    // if ( libshimmer->scaling_enabled() )

    flags |= SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;

    shim.window = sym::SDL_CreateWindow ( wtitle.c_str(),
                                          coords.x,
                                          coords.y,
                                          dims.width,
                                          dims.height,
                                          flags );

    return shim.window;
}

SDL_Renderer* SDL_CreateRenderer ( SDL_Window* window,
                                   int         index,
                                   Uint32      flags ) {
    SHIM_LOG ( 10 );

    shim.renderer = sym::SDL_CreateRenderer ( window, -1,
                                              SDL_RENDERER_ACCELERATED |
                                              SDL_RENDERER_TARGETTEXTURE );

    init_shimmer();

    set_application_render_target();

    return shim.renderer;
}

int SDL_CreateWindowAndRenderer ( int            width,
                                  int            height,
                                  Uint32         window_flags,
                                  SDL_Window**   window,
                                  SDL_Renderer** renderer ) {
    SHIM_LOG ( 10 );

    shim.window = SDL_CreateWindow ( "SDL2 Application",
                                     0,
                                     0,
                                     width,
                                     height,
                                     window_flags );

    if ( !shim.window ) {
        return -1;
    }

    shim.renderer = SDL_CreateRenderer ( shim.window,
                                         -1,
                                         SDL_RENDERER_ACCELERATED |
                                         SDL_RENDERER_TARGETTEXTURE  );

    init_shimmer();

    set_application_render_target();

    return shim.renderer ? 0 : -1;
}

void SDL_RenderPresent ( SDL_Renderer* renderer ) {
    SHIM_LOG ( 10 );

    if ( shim.renderer == renderer ) {
        SDL_SetRenderTarget ( shim.renderer, nullptr );

        libshimmer->refresh_display();
        sym::SDL_RenderPresent ( renderer );

        SDL_SetRenderTarget ( shim.renderer, shim.target );
    }
    else {
        sym::SDL_RenderPresent ( renderer );
    }
}

void SDL_GL_SwapWindow ( SDL_Window* window ) {
    SHIM_LOG ( 1 );
    sym::SDL_GL_SwapWindow ( window );
}

void SDL_SetWindowTitle ( SDL_Window* window,
                          const char* title ) {
    std::string wtitle = title;
    libshimmer->set_window_title ( wtitle );
    sym::SDL_SetWindowTitle ( window, wtitle.c_str() );
}

int SDL_SetWindowDisplayMode ( SDL_Window*            window,
                               const SDL_DisplayMode* mode ) {
    SHIM_LOG ( 10 );

    return sym::SDL_SetWindowDisplayMode ( window, mode );
}

void SDL_DestroyWindow ( SDL_Window* window ) {
    SHIM_LOG ( 10 );

    // if ( shim.window != window ) {
    sym::SDL_DestroyWindow ( window );

    // }
}

void SDL_DestroyRenderer ( SDL_Renderer* renderer ) {
    SHIM_LOG ( 10 );

    // if ( shim.renderer != renderer ) {
    sym::SDL_DestroyRenderer ( renderer );

    // }
}

void SDL_GetWindowSize ( SDL_Window* window,
                         int*        w,
                         int*        h ) {
    auto dims = libshimmer->app_surface_dims();

    *w = dims.width;
    *h = dims.height;
}
<commit_msg>[sdl2] Reuse shimmer window and renderer when application request changes.<commit_after>#include "video.h"

#include "SDL_render.h"

#include "debug.h"

void capture_application_target() {
    SDL_GL_BindTexture ( shim.target, nullptr, nullptr );
    libshimmer->capture_application_texture();
}

void set_application_render_target() {
    if ( shim.target ) {
        SDL_DestroyTexture ( shim.target );
    }

    int w, h;

    SDL_GetWindowSize ( shim.window, &w, &h );

    shim.target = SDL_CreateTexture ( shim.renderer,
                                      SDL_PIXELFORMAT_BGRA32,
                                      SDL_TEXTUREACCESS_TARGET,
                                      w, h );

    if ( SDL_SetRenderTarget ( shim.renderer, shim.target ) != 0 ) {
        std::cout << "Could not set render target: "
                  << SDL_GetError() << std::endl;

        std::cout << glpp::gl_framebuffer_status_to_string (
            glpp::framebuffer::check_status() ) << "\n";
    }

    capture_application_target();
}

void init_shimmer() {
    if ( !shim.opengl_initiliased ) {
        glewExperimental = GL_TRUE;

        GLenum glew_err = glewInit();

        if ( glew_err ) {
            std::cerr << "Error) Unable to initialise GLEW: "
                      << glewGetErrorString ( glew_err ) << std::endl;
        }

        shim.opengl_initiliased = true;
    }

    libshimmer->init_renderer();
}

SDL_Window* SDL_CreateWindow ( const char* title,
                               int         x,
                               int         y,
                               int         w,
                               int         h,
                               Uint32      flags ) {
    SHIM_LOG ( 2 );

    std::string wtitle = title;
    glpp::coords_2i coords ( x, y );
    glpp::dims_2u   dims ( w, h );
    libshimmer->create_window ( wtitle, coords, dims );

    if ( !shim.window ) {
        // if ( libshimmer->scaling_enabled() )

        flags |= SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;

        shim.window = sym::SDL_CreateWindow ( wtitle.c_str(),
                                              coords.x,
                                              coords.y,
                                              dims.width,
                                              dims.height,
                                              flags );
    }
    else {
        set_application_render_target();
    }

    return shim.window;
}

SDL_Renderer* SDL_CreateRenderer ( SDL_Window* window,
                                   int         index,
                                   Uint32      flags ) {
    SHIM_LOG ( 10 );

    if (  shim.window == window  ) {
        if ( !shim.renderer ) {
            shim.renderer = sym::SDL_CreateRenderer ( window, -1,
                                                      SDL_RENDERER_ACCELERATED |
                                                      SDL_RENDERER_TARGETTEXTURE );

            init_shimmer();

            set_application_render_target();
        }

        return shim.renderer;
    }

    return sym::SDL_CreateRenderer ( window, index, flags );
}

int SDL_CreateWindowAndRenderer ( int            width,
                                  int            height,
                                  Uint32         window_flags,
                                  SDL_Window**   window,
                                  SDL_Renderer** renderer ) {
    SHIM_LOG ( 10 );

    SDL_CreateWindow ( "SDL2 Application", 0, 0, width, height, window_flags );

    if ( !shim.window ) return -1;

    SDL_CreateRenderer ( shim.window, 0, 0 );

    return shim.renderer ? 0 : -1;
}

void SDL_RenderPresent ( SDL_Renderer* renderer ) {
    SHIM_LOG ( 10 );

    if ( shim.renderer == renderer ) {
        SDL_SetRenderTarget ( shim.renderer, nullptr );

        libshimmer->refresh_display();
        sym::SDL_RenderPresent ( renderer );

        SDL_SetRenderTarget ( shim.renderer, shim.target );
    }
    else {
        sym::SDL_RenderPresent ( renderer );
    }
}

void SDL_GL_SwapWindow ( SDL_Window* window ) {
    SHIM_LOG ( 1 );
    sym::SDL_GL_SwapWindow ( window );
}

void SDL_SetWindowTitle ( SDL_Window* window,
                          const char* title ) {
    std::string wtitle = title;
    libshimmer->set_window_title ( wtitle );
    sym::SDL_SetWindowTitle ( window, wtitle.c_str() );
}

int SDL_SetWindowDisplayMode ( SDL_Window*            window,
                               const SDL_DisplayMode* mode ) {
    SHIM_LOG ( 10 );

    return sym::SDL_SetWindowDisplayMode ( window, mode );
}

void SDL_DestroyWindow ( SDL_Window* window ) {
    SHIM_LOG ( 10 );

    if ( shim.window != window ) {
        sym::SDL_DestroyWindow ( window );
    }
}

void SDL_DestroyRenderer ( SDL_Renderer* renderer ) {
    SHIM_LOG ( 10 );

    if ( shim.renderer != renderer ) {
        sym::SDL_DestroyRenderer ( renderer );
    }
}

void SDL_GetWindowSize ( SDL_Window* window,
                         int*        w,
                         int*        h ) {
    auto dims = libshimmer->app_surface_dims();

    *w = dims.width;
    *h = dims.height;
}
<|endoftext|>


<commit_before>#ifdef BARRELFISH
extern "C" {
#include <lua/lua.h>
#include <lua/lualib.h>
#include <lua/lauxlib.h>
}
#else
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#endif

#include <cstdio>
#include <cassert>
#include <cstring>

#include "shl_internal.h"
#include "shl_timer.hpp"

/**
 *
 */
const char* shl__arr_feature_table[] = {
    "partitioning",
    "replication",
    "distribution",
    "hugepage"
};

#ifdef BARRELFISH
//static const char* SETTINGS_FILE = "/nfs/array_settings.lua";
#else
static const char* SETTINGS_FILE = "settings.lua";
#endif

///<
static lua_State *L = NULL;

///<
static Timer lua_timer;

#if 0
// http://windrealm.org/tutorials/reading-a-lua-configuration-file-from-c.php
static const char* shl__lua_stringexpr(lua_State* lua, const char* expr, const char* def)
{

    const char* r = def;
    char buf[256] = "";

    /* Assign the Lua expression to a Lua global variable. */
    sprintf(buf, "evalExpr=%s", expr);
    if (!luaL_dostring(lua, buf)) {

        /* Get the value of the global varibable */
        lua_getglobal(lua, "evalExpr");
        if (lua_isstring(lua, -1)) {
            r = lua_tostring(lua, -1);
        }

        /* remove lua_getglobal value */
        lua_pop(lua, 1);
    }

    return r;
}
#endif

/**
 *
 * @param lua
 * @param expr
 * @param def_val
 * @return
 */
static int shl__lua_boolexpr(lua_State* lua, const char* expr, bool def_val)
{
    int ok = def_val;
    char buf[256] = "";

    /* Assign the Lua expression to a Lua global variable. */

    printf("Querying [%s] ..", expr);

    sprintf(buf, "evalExpr=%s", expr);

    if (!luaL_dostring(lua, buf)) {

        /* Get the value of the global varibable */

        lua_getglobal(lua, "evalExpr");

        if (lua_isboolean(lua, -1)) {
            ok = lua_toboolean(lua, -1);
            printf(" .. found %d", ok);
        }

        /* remove lua_getglobal value */

        lua_pop(lua, 1);

    }

    printf(" .. result %d\n", ok);

    return ok;

}

/**
 * \brief Return array feature configuration for given array
 */
bool shl__get_array_conf(const char *array_name, int feature, bool def)
{
    lua_timer.start();
    assert(strlen(array_name) < SHL__ARRAY_NAME_LEN_MAX);
    assert(strncmp(array_name, "shl__", 5) == 0);

    array_name = array_name + strlen("shl__");

    char tmp[256 + SHL__ARRAY_NAME_LEN_MAX];

    sprintf(tmp, "settings.arrays[\"%s\"].%s", array_name,
            shl__arr_feature_table[feature]);

    bool res = shl__lua_boolexpr(L, tmp, def);
    lua_timer.stop();

    return res;
}

/**
 *
 */
void shl__lua_init(void)
{
    lua_timer.start();
#ifndef BARRELFISH
    L = luaL_newstate();
    if (L) {
        luaL_openlibs(L);
    } else {
        printf("ERROR: opening LUA\n");
    }

    // Load settings file
    if ( luaL_dofile( L, SETTINGS_FILE ) == 1) {
        printf("Error loading %s\n", SETTINGS_FILE);
        assert(!"Error loading settings-file. Check it's syntax.");
    }

    // luaL_loadbuffer(L, program, strlen(program), "line")
#endif
    lua_timer.stop();
}

/**
 *
 */
void shl__lua_deinit(void)
{
    lua_close(L);
    L = NULL;
    printf("LUA done (time spent: %f)\n", lua_timer.get());
}
<commit_msg>reverted ifdef of lua init<commit_after>#ifdef BARRELFISH
extern "C" {
#include <lua/lua.h>
#include <lua/lualib.h>
#include <lua/lauxlib.h>
}
#else
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#endif

#include <cstdio>
#include <cassert>
#include <cstring>

#include "shl_internal.h"
#include "shl_timer.hpp"

/**
 *
 */
const char* shl__arr_feature_table[] = {
    "partitioning",
    "replication",
    "distribution",
    "hugepage"
};

#ifdef BARRELFISH
static const char* SETTINGS_FILE = "/nfs/array_settings.lua";
#else
static const char* SETTINGS_FILE = "settings.lua";
#endif

///<
static lua_State *L = NULL;

///<
static Timer lua_timer;

#if 0
// http://windrealm.org/tutorials/reading-a-lua-configuration-file-from-c.php
static const char* shl__lua_stringexpr(lua_State* lua, const char* expr, const char* def)
{

    const char* r = def;
    char buf[256] = "";

    /* Assign the Lua expression to a Lua global variable. */
    sprintf(buf, "evalExpr=%s", expr);
    if (!luaL_dostring(lua, buf)) {

        /* Get the value of the global varibable */
        lua_getglobal(lua, "evalExpr");
        if (lua_isstring(lua, -1)) {
            r = lua_tostring(lua, -1);
        }

        /* remove lua_getglobal value */
        lua_pop(lua, 1);
    }

    return r;
}
#endif

/**
 *
 * @param lua
 * @param expr
 * @param def_val
 * @return
 */
static int shl__lua_boolexpr(lua_State* lua, const char* expr, bool def_val)
{
    int ok = def_val;
    char buf[256] = "";

    /* Assign the Lua expression to a Lua global variable. */

    printf("Querying [%s] ..", expr);

    sprintf(buf, "evalExpr=%s", expr);

    if (!luaL_dostring(lua, buf)) {

        /* Get the value of the global varibable */

        lua_getglobal(lua, "evalExpr");

        if (lua_isboolean(lua, -1)) {
            ok = lua_toboolean(lua, -1);
            printf(" .. found %d", ok);
        }

        /* remove lua_getglobal value */

        lua_pop(lua, 1);

    }

    printf(" .. result %d\n", ok);

    return ok;

}

/**
 * \brief Return array feature configuration for given array
 */
bool shl__get_array_conf(const char *array_name, int feature, bool def)
{
    lua_timer.start();
    assert(strlen(array_name) < SHL__ARRAY_NAME_LEN_MAX);
    assert(strncmp(array_name, "shl__", 5) == 0);

    array_name = array_name + strlen("shl__");

    char tmp[256 + SHL__ARRAY_NAME_LEN_MAX];

    sprintf(tmp, "settings.arrays[\"%s\"].%s", array_name,
            shl__arr_feature_table[feature]);

    bool res = shl__lua_boolexpr(L, tmp, def);
    lua_timer.stop();

    return res;
}

/**
 *
 */
void shl__lua_init(void)
{
    lua_timer.start();
    L = luaL_newstate();
    if (L) {
        luaL_openlibs(L);
    } else {
        printf("ERROR: opening LUA\n");
    }

    // Load settings file
    if ( luaL_dofile( L, SETTINGS_FILE ) == 1) {
        printf("Error loading %s\n", SETTINGS_FILE);
        assert(!"Error loading settings-file. Check it's syntax.");
    }

    // luaL_loadbuffer(L, program, strlen(program), "line")
    lua_timer.stop();
}

/**
 *
 */
void shl__lua_deinit(void)
{
    lua_close(L);
    L = NULL;
    printf("LUA done (time spent: %f)\n", lua_timer.get());
}
<|endoftext|>


<commit_before>/*
*soundplayer.cpp: Many helpful sound functions.
By 2MB Solutions: https//2mb.solutions
Released under the MIT license. See license.txt for details.
Billy: https://stormdragon.tk/
Michael: https://michaeltaboada.me
*/
#include <allegro5/allegro.h>
#include "dynamic_menu.h"
#include <keyboard.h>
#include <sound.h>
#include <string>
#include <misc.h>
#include <menu_helper.h>
#include "soundplayer.h"

int power_bar(string soundstring, int p, int min, int max, float wait)
{
sound s;
if(!s.load(soundstring)) {
log("Could not load power bar sound.\n");
return -100;
}
s.set_pitch(min);
s.set_loop(true);
if(!s.play()) {
log("Could not play power bar sound.\n");
return -100;
}
if(p > min-1) {
for(int x = min; x <= p; x++) {
al_rest(wait);
s.set_pitch(s.get_pitch()+1);
}
}
else {
keyboard kb;
int dir = 1;
while(!kb.key_pressed(ALLEGRO_KEY_SPACE)) {
if(kb.key_pressed(ALLEGRO_KEY_ESCAPE) || ((kb.key_down(ALLEGRO_KEY_ALT) || kb.key_down(ALLEGRO_KEY_ALTGR)) && kb.key_pressed(ALLEGRO_KEY_F4))) {
return -100;
}
if (kb.key_pressed(ALLEGRO_KEY_BACKSPACE)) {
return -101;
}
al_rest(wait);
s.set_pitch(s.get_pitch()+dir);
if(s.get_pitch() >= max) {
dir = -1;
}
else if(s.get_pitch() <= min) {
dir = 1;
}
}
}
s.stop();
return s.get_pitch();
}

int direction_bar(string soundstring, int d, int min, int max, float wait)
{
sound s;
if(!s.load(soundstring)) {
log("Could not load direction bar sound.\n");
return -100;
}
s.set_pan(min);
s.set_loop(true);
if(!s.play()) {
log("Could not play direction bar sound.\n");
return -100;
}
if(d >= min && d <= max) {
for (int x = min; x <= d; x++) {
al_rest(wait);
s.set_pan(x);
}
}
else {
keyboard kb;
int dir = 1;
while(!kb.key_pressed(ALLEGRO_KEY_SPACE)) {
if(kb.key_pressed(ALLEGRO_KEY_ESCAPE) || ((kb.key_down(ALLEGRO_KEY_ALT) || kb.key_down(ALLEGRO_KEY_ALTGR)) && kb.key_pressed(ALLEGRO_KEY_F4))) {
return -100;
}
if(kb.key_pressed(ALLEGRO_KEY_BACKSPACE)) {
return -101;
}
al_rest(wait);
s.set_pan(s.get_pan()+dir);
if(s.get_pan() >= max) {
dir = -1;
}
else if(s.get_pan() <= min) {
dir = 1;
}
}
}
s.stop();
return s.get_pan();
}

void fade(sound* s, int start, int end, float time) {
if(!s) {
return;
}
s->set_gain(start);
for(int x = 0; x < time/0.005; x++) {
al_rest(0.005);
s->set_gain(s->get_gain()+((end-start)/(time/0.005)+start));
}
s->stop();
}

bool play_sound_wait(sound* s) {
if(!s->play()) {
log("Could not play sound file.\n");
return false;
}
while(s->is_playing()) {
al_rest(0.005);
}
return true;
}

bool play_sound_wait(string s) {
sound so;
if(!so.load(s)) {
log(((string)("Could not load sound ")+s+".\n").c_str());
return false;
}
else {
return play_sound_wait(&so);
}
}

void learn_sounds() {
vector<string>* vec = get_dir_children("sounds", 1);
vector<string> real_items;
for (int x = 0; x < vec->size(); x++) {
if((*vec)[x].find("-music") == string::npos) {
string temp = (*vec)[x];
int pos = temp.find("-");
while(pos != string::npos) {
temp.replace(pos, 1, " ");
pos = temp.find("-", pos+1);
}
temp.replace(temp.find("."), string::npos, "");
real_items.push_back(temp);
}
else {
vec->erase(vec->begin()+x);
x--;
}
}
real_items.push_back("back to main menu");
dynamic_menu* menu = create_menu(real_items, vector<string>());
int ran = menu->run_extended("", "Use your arrow keys to navigate the menu, and enter to play the sound. Pressing space while the sound is playing will stop it.", 1, true);
keyboard kb;
while(ran != -1 && ran != 0 && ran != real_items.size()) {
sound s;
s.load((string)("sounds/")+(*vec)[ran-1]);
s.play();
while(s.is_playing()) {
if(kb.key_pressed(ALLEGRO_KEY_SPACE)) {
break;
}
}
s.stop();
ran = menu->run_extended("", "", ran, false);
}
delete vec;
delete menu;
}

<commit_msg>Hopefully fixed crashes.<commit_after>/*
*soundplayer.cpp: Many helpful sound functions.
By 2MB Solutions: https//2mb.solutions
Released under the MIT license. See license.txt for details.
Billy: https://stormdragon.tk/
Michael: https://michaeltaboada.me
*/
#include <allegro5/allegro.h>
#include "dynamic_menu.h"
#include <keyboard.h>
#include <sound.h>
#include <string>
#include <misc.h>
#include <menu_helper.h>
#include "soundplayer.h"

int power_bar(string soundstring, int p, int min, int max, float wait)
{
sound s;
if(!s.load(soundstring)) {
log("Could not load power bar sound.\n");
return -100;
}
s.set_pitch(min);
s.set_loop(true);
if(!s.play()) {
log("Could not play power bar sound.\n");
return -100;
}
if(p > min-1) {
for(int x = min; x <= p; x++) {
al_rest(wait);
s.set_pitch(s.get_pitch()+1);
}
}
else {
keyboard kb;
int dir = 1;
while(!kb.key_pressed(ALLEGRO_KEY_SPACE)) {
if(kb.key_pressed(ALLEGRO_KEY_ESCAPE) || ((kb.key_down(ALLEGRO_KEY_ALT) || kb.key_down(ALLEGRO_KEY_ALTGR)) && kb.key_pressed(ALLEGRO_KEY_F4))) {
return -100;
}
if (kb.key_pressed(ALLEGRO_KEY_BACKSPACE)) {
return -101;
}
al_rest(wait);
s.set_pitch(s.get_pitch()+dir);
if(s.get_pitch() >= max) {
dir = -1;
}
else if(s.get_pitch() <= min) {
dir = 1;
}
}
}
s.stop();
return s.get_pitch();
}

int direction_bar(string soundstring, int d, int min, int max, float wait)
{
sound s;
if(!s.load(soundstring)) {
log("Could not load direction bar sound.\n");
return -100;
}
s.set_pan(min);
s.set_loop(true);
if(!s.play()) {
log("Could not play direction bar sound.\n");
return -100;
}
if(d >= min && d <= max) {
for (int x = min; x <= d; x++) {
al_rest(wait);
s.set_pan(x);
}
}
else {
keyboard kb;
int dir = 1;
while(!kb.key_pressed(ALLEGRO_KEY_SPACE)) {
if(kb.key_pressed(ALLEGRO_KEY_ESCAPE) || ((kb.key_down(ALLEGRO_KEY_ALT) || kb.key_down(ALLEGRO_KEY_ALTGR)) && kb.key_pressed(ALLEGRO_KEY_F4))) {
return -100;
}
if(kb.key_pressed(ALLEGRO_KEY_BACKSPACE)) {
return -101;
}
al_rest(wait);
s.set_pan(s.get_pan()+dir);
if(s.get_pan() >= max) {
dir = -1;
}
else if(s.get_pan() <= min) {
dir = 1;
}
}
}
s.stop();
return s.get_pan();
}

void fade(sound* s, int start, int end, float time) {
if(!s) {
return;
}
s->set_gain(start);
for(int x = 0; x < time/0.005; x++) {
al_rest(0.005);
s->set_gain(s->get_gain()+((end-start)/(time/0.005)+start));
}
s->stop();
}

bool play_sound_wait(sound* s) {
if(!s->play()) {
log("Could not play sound file.\n");
return false;
}
while(s->is_playing()) {
al_rest(0.005);
}
return true;
}

bool play_sound_wait(string s) {
sound so;
if(!so.load(s)) {
log(((string)("Could not load sound ")+s+".\n").c_str());
return false;
}
else {
return play_sound_wait(&so);
}
}

void learn_sounds() {
vector<string>* vec = get_dir_children("sounds", 1);
vector<string> real_items;
if (vec) {
for (int x = 0; x < vec->size(); x++) {
if((*vec)[x].find("-music") == string::npos) {
string temp = (*vec)[x];
int pos = temp.find("-");
while(pos != string::npos) {
temp.replace(pos, 1, " ");
pos = temp.find("-", pos+1);
}
temp.replace(temp.find("."), string::npos, "");
real_items.push_back(temp);
}
else {
vec->erase(vec->begin()+x);
x--;
}
}
real_items.push_back("back to main menu");
dynamic_menu* menu = create_menu(real_items, vector<string>());
int ran = menu->run_extended("", "Use your arrow keys to navigate the menu, and enter to play the sound. Pressing space while the sound is playing will stop it.", 1, true);
keyboard kb;
while(ran != -1 && ran != 0 && ran != real_items.size()) {
sound s;
s.load((string)("sounds/")+(*vec)[ran-1]);
s.play();
while(s.is_playing()) {
if(kb.key_pressed(ALLEGRO_KEY_SPACE)) {
break;
}
}
s.stop();
ran = menu->run_extended("", "", ran, false);
}
delete vec;
delete menu;
}
else {
log("Learn game sounds: the vector returned was NULL!\n");
}
}

<|endoftext|>


<commit_before>#ifndef CAMERA_H
#define CAMERA_H

#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>

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

static const int devid = 0;

class Camera
{
private:
  void operator=(const Camera&){};
  Camera(const Camera&){};
  int makeTimePath();
  cv::Mat rmNoize(cv::Mat src);
  cv::VideoCapture capture(int devid);
  std::string timePath;
  cv::Mat input;//入力画像
  cv::Mat output;//出力画像
public:
  Camera();
  ~Camera();
  int takePhoto();
  int binarize();
  double countArea();
  double getCenter();
};

#endif
<commit_msg>dbeug<commit_after>#ifndef CAMERA_H
#define CAMERA_H

#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>

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

class Camera
{
private:
  void operator=(const Camera&){};
  Camera(const Camera&){};
  int makeTimePath();
  cv::Mat rmNoize(cv::Mat src);
  cv::VideoCapture capture(0);
  std::string timePath;
  cv::Mat input;//入力画像
  cv::Mat output;//出力画像
public:
  Camera();
  ~Camera();
  int takePhoto();
  int binarize();
  double countArea();
  double getCenter();
};

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include "mnist.hpp"
#include "timing.hpp"
#include "network.hpp"

int main()
{
	// RELU - tops at ~84%, eta = 0.05, batch_size = 30, 100 (seems to not matter much)
	// Sigmoid - tops at ~98%, eta = 2.0, 1.0, 0.5 (<0.96,<0.97,<1.0), batch_size = 10
	{
		using namespace nn;
		network net;
		constexpr ActivationType type = ActivationType::kSigmoid;

		net.addInputLayer<type>(28 * 28);
		net.addRegularLayer<type, WeightInitializationType::kWeightedGaussian>(50);
		net.addRegularLayer<type, WeightInitializationType::kWeightedGaussian>(10);

		std::vector<MatrixType> training_set, validation_set;
		std::vector<uint8_t> training_labels, validation_labels;
		const size_t dataset_size = 60000;
		{
			const auto images = loadMNISTImages("externals/mnist/train-images.idx3-ubyte", dataset_size);
			const auto labels = loadMNISTLabels("externals/mnist/train-labels.idx1-ubyte", dataset_size);
			training_set = std::vector<MatrixType>(images.cbegin(), images.cbegin() + 50000);
			validation_set = std::vector<MatrixType>(images.cbegin() + 50000, images.cend());
			training_labels = std::vector<uint8_t>(labels.cbegin(), labels.cbegin() + 50000);
			validation_labels = std::vector<uint8_t>(labels.cbegin() + 50000, labels.cend());
		}
		const size_t epochs = 30;
		const size_t batch_size = 10;
		real eta = 2.0f;
		// SGD
		timing timer;
		for (size_t epoch = 0u; epoch < epochs; ++epoch)
		{
			const size_t batches = training_set.size() / batch_size;
			MatrixType image_batch = MatrixType::Zero(28 * 28, batch_size);
			std::vector<uint8_t> label_batch(batch_size);
			for (size_t k = 0u; k < batches; k++)
			{
				const size_t batch_start = k * batch_size;
				const size_t batch_end = (k + 1) * batch_size;

				for (size_t i = batch_start; i < batch_end; ++i)
				{
					image_batch.col(i - batch_start) = training_set[i];
					label_batch[i - batch_start] = training_labels[i];
				}
				net.feedforward(image_batch);
				net.backprop(label_batch);
				net.update_weights(eta, batch_size);
			}
			real correct = net.evaluate(validation_set, validation_labels);
			// learning rate slow down at peak accuracy
			if (correct > 0.96) eta = 1.0f;
			if (correct > 0.97) eta = 0.5f;
			std::cout << "Epoch " << epoch << ", acc: " << correct * 100.0f << "% (" << timer.seconds() << " seconds passed)" << std::endl;
		}
	}
	int x;
	std::cin >> x;
	return 0;
}<commit_msg>do not allocate memory inside the epoch loop<commit_after>#include <iostream>
#include "mnist.hpp"
#include "timing.hpp"
#include "network.hpp"

int main()
{
	// RELU - tops at ~84%, eta = 0.05, batch_size = 30, 100 (seems to not matter much)
	// Sigmoid - tops at ~98%, eta = 2.0, 1.0, 0.5 (<0.96,<0.97,<1.0), batch_size = 10
	{
		using namespace nn;
		network net;
		constexpr ActivationType type = ActivationType::kSigmoid;

		net.addInputLayer<type>(28 * 28);
		net.addRegularLayer<type, WeightInitializationType::kWeightedGaussian>(50);
		net.addRegularLayer<type, WeightInitializationType::kWeightedGaussian>(10);

		std::vector<MatrixType> training_set, validation_set;
		std::vector<uint8_t> training_labels, validation_labels;
		const size_t dataset_size = 60000;
		{
			const auto images = loadMNISTImages("externals/mnist/train-images.idx3-ubyte", dataset_size);
			const auto labels = loadMNISTLabels("externals/mnist/train-labels.idx1-ubyte", dataset_size);
			training_set = std::vector<MatrixType>(images.cbegin(), images.cbegin() + 50000);
			validation_set = std::vector<MatrixType>(images.cbegin() + 50000, images.cend());
			training_labels = std::vector<uint8_t>(labels.cbegin(), labels.cbegin() + 50000);
			validation_labels = std::vector<uint8_t>(labels.cbegin() + 50000, labels.cend());
		}
		const size_t epochs = 30;
		const size_t batch_size = 10;
		real eta = 2.0f;
		// SGD
		timing timer;
		const size_t batches = training_set.size() / batch_size;
		MatrixType image_batch = MatrixType::Zero(28 * 28, batch_size);
		std::vector<uint8_t> label_batch(batch_size);
		for (size_t epoch = 0u; epoch < epochs; ++epoch)
		{
			for (size_t k = 0u; k < batches; k++)
			{
				const size_t batch_start = k * batch_size;
				const size_t batch_end = (k + 1) * batch_size;

				for (size_t i = batch_start; i < batch_end; ++i)
				{
					image_batch.col(i - batch_start) = training_set[i];
					label_batch[i - batch_start] = training_labels[i];
				}
				net.feedforward(image_batch);
				net.backprop(label_batch);
				net.update_weights(eta, batch_size);
			}
			real correct = net.evaluate(validation_set, validation_labels);
			// learning rate slow down at peak accuracy
			if (correct > 0.96) eta = 1.0f;
			if (correct > 0.97) eta = 0.5f;
			std::cout << "Epoch " << epoch << ", acc: " << correct * 100.0f << "% (" << timer.seconds() << " seconds passed)" << std::endl;
		}
	}
	int x;
	std::cin >> x;
	return 0;
}<|endoftext|>


<commit_before>#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgcodecs.hpp>

#include <opencv2/videoio/videoio_c.h>
#include <opencv2/highgui/highgui_c.h>

#include <cctype>
#include <iostream>
#include <fstream>
#include <iterator>

#include <stdio.h>
#include "svg_image.h"

using namespace std;
//using namespace cv;

const char * help_string = "\
## Swap faces from a picture with a set of faces from choice ##
This program assumes hardcoded paths: \n\
- source -- must be current dir \n\
    - faceswap -- executable \n\
    - file-template.xml \n\
    - img-template.xml \n\
    - [source code] \n\
- photo_result -- will cointain the svg's \n\
    - *.svg -- refers to images with relative paths \n\
- haarcascades -- image recongnition data \n\
    - haarcascade_frontalface_alt.xml \n\
    - haarcascade_frontalface_alt2.xml \n\
    - haarcascade_frontalface_alt_tree.xml \n\
    - haarcascade_frontalface_default.xml \n\
    - ... \n\
- photo_heads -- contains the photos's of heads you want to set_rect \n\
    - *.png \n\
- photos -- for the sake of path's in the SVG file it's advised to place your pictures here \n\
 \n\
The outputted SVG is viewed best with a browser. \n\
";

std::vector<cv::Rect> detectAndDraw( cv::Mat& image, cv::CascadeClassifier& cascade,
    double scale, bool tryflip );

const char* cascadeNames[] =  {
    "../haarcascades/haarcascade_frontalface_alt.xml",
    "../haarcascades/haarcascade_frontalface_alt2.xml",
    "../haarcascades/haarcascade_frontalface_alt_tree.xml",
    "../haarcascades/haarcascade_frontalface_default.xml"
};

std::string file_original = "../photos/pic_example.jpg";
std::string file_target_svg = "../photo_result/default_path.svg";

std::string MakeTargetSvgPath(std::string original)
{
  std::size_t pos = original.find_last_of("/");      // position of "live" in str
  auto str_tmp =  original.substr (pos, original.length()-pos-3);     // get from "live" to the end
  return std::string("../photo_result") + str_tmp + "svg";
}

int main( int argc, const char** argv )
{
    const string scaleOpt = "--scale=";
    size_t scaleOptLen = scaleOpt.length();

    const string photoOpt = "--photo=";
    size_t photoOptLen = photoOpt.length();

    const string cascadeOpt = "--cascade=";
    size_t cascadeOptLen = cascadeOpt.length();

    const string helpOpt = "--help";
    size_t helpOptLen = helpOpt.length();

    const string tryFlipOpt = "--try-flip";
    size_t tryFlipOptLen = tryFlipOpt.length();

    bool tryflip = false;
    double scale = 1;

    for( int i = 1; i < argc; i++ )
    {
        cout << "Argument " << i << ": " <<  argv[i] << endl;
        if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
        {
            cascadeNames[0] = argv[i];
            cout << "  from which we have cascade1Name= " << cascadeNames[0] << endl;
        }
        else if( photoOpt.compare( 0, photoOptLen, argv[i], photoOptLen ) == 0 )
        {
            if( !sscanf( argv[i] + photoOpt.length(), "%lf", &scale ) || scale < 1 )
                file_original = string(argv[i]);
            cout << " from which we read scale = " << file_original << endl;
        }
        else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
        {
            if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
                scale = 1;
            cout << " from which we read scale = " << scale << endl;
        }
        else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
        {
            tryflip = true;
            cout << " will try to flip image horizontally to detect assymetric objects\n";
        }
        else if( helpOpt.compare( 0, helpOptLen, argv[i], helpOptLen ) == 0 )
        {
            cout << help_string;
            cout << "Using OpenCV version " << CV_VERSION << "\n" << endl;
            return 0;
        }
        else if( argv[i][0] == '-' )
        {
            cerr << "WARNING: Unknown option " << argv[i] << endl;
        }
        else
            file_original.assign( argv[i] );
    }

    file_target_svg = MakeTargetSvgPath(file_original);
    cout << "Output ile: " << file_target_svg << endl;
    // End of freacking input stuff //

    vector<cv::CascadeClassifier> cascades;
    for( unsigned int i = 0; i<4; ++i){
        cascades.push_back(cv::CascadeClassifier());
        if( !cascades[i].load( cascadeNames[i] ) )
        {
            cerr << "ERROR: Could not load cascade " << cascadeNames[i] << endl;
            return -1;
        }
    }

    cv::Mat image = cv::imread(file_original);   // Read the file
    if(!image.data )
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

    std::vector<cv::Rect> faces_all, faces;

    faces = detectAndDraw( image, cascades[1], scale, tryflip );
    faces_all.insert(faces_all.end(), faces.begin(), faces.end());

    //faces = detectAndDraw( image, cascade, scale, tryflip );
    //faces_all.insert(faces_all.end(), faces.begin(), faces.end());

    std::stringstream ss("", ios_base::app | ios_base::out);

    for(auto r : faces_all)
    {
        // messy object, I know, I know
        auto svgimage = svg_image();
        svgimage.refresh();
        svgimage.set_rect(r);
        ss << svgimage.get_resulting_svg();
    }

    auto file_content = file_to_string("file-template.xml");
    replace_var(file_content, "$original_picture_here", file_original);
    replace_var(file_content, "$img_attributes_here", ss.str());
    replace_var(file_content, "$image_width", std::to_string(image.cols));
    replace_var(file_content, "$image_height", std::to_string(image.rows));

    ofstream myfile;
    myfile.open (file_target_svg, ios::out);
    myfile << file_content;
    myfile.close();

    return 0;
}

std::vector<cv::Rect> detectAndDraw( cv::Mat& image, cv::CascadeClassifier& cascade,
    double scale, bool tryflip)
{
    cv::Mat imgCopy( cvRound(image.rows/scale), cvRound(image.cols/scale), CV_8UC1 );
    //cv::Mat imgCopy( 732*0.8, 1100*0.8, CV_8UC1 );
    //Size( std::min (image.rows, 100), std::min(image.cols, 100) )
    cv::Mat imgGray;
    cv::cvtColor( image, imgGray, cv::COLOR_BGR2GRAY );
    cv::resize( imgGray, imgCopy, imgCopy.size()  , 0, 0, cv::INTER_LINEAR );
    cv::equalizeHist( imgCopy, imgCopy );

    vector<cv::Rect> faces;
    cascade.detectMultiScale( imgCopy, faces,
        1.1, 2, 0
        //|cv::CASCADE_FIND_BIGGEST_OBJECT
        //|cv::CASCADE_DO_ROUGH_SEARCH
        |cv::CASCADE_SCALE_IMAGE
        ,
        cv::Size(11, 11) );
    if( tryflip )
    {
        vector<cv::Rect> faces_fliped;
        cv::flip(imgCopy, imgCopy, 1);
        cascade.detectMultiScale( imgCopy, faces_fliped,
         1.1, 2, 0
            //|cv::CASCADE_FIND_BIGGEST_OBJECT
            //|cv::CASCADE_DO_ROUGH_SEARCH
         |cv::CASCADE_SCALE_IMAGE
         ,
         cv::Size(17, 17) );

        faces.insert(faces.end(), faces_fliped.begin(), faces_fliped.end());
    }

    cout << "Number of faces: " << faces.size() << endl;

    return faces;
}
<commit_msg>fixed help_string<commit_after>#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgcodecs.hpp>

#include <opencv2/videoio/videoio_c.h>
#include <opencv2/highgui/highgui_c.h>

#include <cctype>
#include <iostream>
#include <fstream>
#include <iterator>

#include <stdio.h>
#include "svg_image.h"

using namespace std;
//using namespace cv;

const char * help_string = "\
## Swap faces from a picture with a set of faces from choice ## \n\
This program assumes hardcoded paths: \n\
- source -- must be current dir \n\
    - faceswap -- executable \n\
    - file-template.xml \n\
    - img-template.xml \n\
    - [source code] \n\
- photo_result -- will cointain the svg's \n\
    - *.svg -- refers to images with relative paths \n\
- haarcascades -- image recongnition data \n\
    - haarcascade_frontalface_alt.xml \n\
    - haarcascade_frontalface_alt2.xml \n\
    - haarcascade_frontalface_alt_tree.xml \n\
    - haarcascade_frontalface_default.xml \n\
    - ... \n\
- photo_heads -- contains the photos's of heads you want to set_rect \n\
    - *.png \n\
- photos -- for the sake of path's in the SVG file it's advised to place your pictures here \n\
 \n\
The outputted SVG is viewed best with a browser. \n\
";

std::vector<cv::Rect> detectAndDraw( cv::Mat& image, cv::CascadeClassifier& cascade,
    double scale, bool tryflip );

const char* cascadeNames[] =  {
    "../haarcascades/haarcascade_frontalface_alt.xml",
    "../haarcascades/haarcascade_frontalface_alt2.xml",
    "../haarcascades/haarcascade_frontalface_alt_tree.xml",
    "../haarcascades/haarcascade_frontalface_default.xml"
};

std::string file_original = "../photos/pic_example.jpg";
std::string file_target_svg = "../photo_result/default_path.svg";

std::string MakeTargetSvgPath(std::string original)
{
  std::size_t pos = original.find_last_of("/");      // position of "live" in str
  auto str_tmp =  original.substr (pos, original.length()-pos-3);     // get from "live" to the end
  return std::string("../photo_result") + str_tmp + "svg";
}

int main( int argc, const char** argv )
{
    const string scaleOpt = "--scale=";
    size_t scaleOptLen = scaleOpt.length();

    const string photoOpt = "--photo=";
    size_t photoOptLen = photoOpt.length();

    const string cascadeOpt = "--cascade=";
    size_t cascadeOptLen = cascadeOpt.length();

    const string helpOpt = "--help";
    size_t helpOptLen = helpOpt.length();

    const string tryFlipOpt = "--try-flip";
    size_t tryFlipOptLen = tryFlipOpt.length();

    bool tryflip = false;
    double scale = 1;

    for( int i = 1; i < argc; i++ )
    {
        cout << "Argument " << i << ": " <<  argv[i] << endl;
        if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
        {
            cascadeNames[0] = argv[i];
            cout << "  from which we have cascade1Name= " << cascadeNames[0] << endl;
        }
        else if( photoOpt.compare( 0, photoOptLen, argv[i], photoOptLen ) == 0 )
        {
            if( !sscanf( argv[i] + photoOpt.length(), "%lf", &scale ) || scale < 1 )
                file_original = string(argv[i]);
            cout << " from which we read scale = " << file_original << endl;
        }
        else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
        {
            if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
                scale = 1;
            cout << " from which we read scale = " << scale << endl;
        }
        else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
        {
            tryflip = true;
            cout << " will try to flip image horizontally to detect assymetric objects\n";
        }
        else if( helpOpt.compare( 0, helpOptLen, argv[i], helpOptLen ) == 0 )
        {
            cout << help_string;
            cout << "Using OpenCV version " << CV_VERSION << "\n" << endl;
            return 0;
        }
        else if( argv[i][0] == '-' )
        {
            cerr << "WARNING: Unknown option " << argv[i] << endl;
        }
        else
            file_original.assign( argv[i] );
    }

    file_target_svg = MakeTargetSvgPath(file_original);
    cout << "Output ile: " << file_target_svg << endl;
    // End of freacking input stuff //

    vector<cv::CascadeClassifier> cascades;
    for( unsigned int i = 0; i<4; ++i){
        cascades.push_back(cv::CascadeClassifier());
        if( !cascades[i].load( cascadeNames[i] ) )
        {
            cerr << "ERROR: Could not load cascade " << cascadeNames[i] << endl;
            return -1;
        }
    }

    cv::Mat image = cv::imread(file_original);   // Read the file
    if(!image.data )
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

    std::vector<cv::Rect> faces_all, faces;

    faces = detectAndDraw( image, cascades[1], scale, tryflip );
    faces_all.insert(faces_all.end(), faces.begin(), faces.end());

    //faces = detectAndDraw( image, cascade, scale, tryflip );
    //faces_all.insert(faces_all.end(), faces.begin(), faces.end());

    std::stringstream ss("", ios_base::app | ios_base::out);

    for(auto r : faces_all)
    {
        // messy object, I know, I know
        auto svgimage = svg_image();
        svgimage.refresh();
        svgimage.set_rect(r);
        ss << svgimage.get_resulting_svg();
    }

    auto file_content = file_to_string("file-template.xml");
    replace_var(file_content, "$original_picture_here", file_original);
    replace_var(file_content, "$img_attributes_here", ss.str());
    replace_var(file_content, "$image_width", std::to_string(image.cols));
    replace_var(file_content, "$image_height", std::to_string(image.rows));

    ofstream myfile;
    myfile.open (file_target_svg, ios::out);
    myfile << file_content;
    myfile.close();

    return 0;
}

std::vector<cv::Rect> detectAndDraw( cv::Mat& image, cv::CascadeClassifier& cascade,
    double scale, bool tryflip)
{
    cv::Mat imgCopy( cvRound(image.rows/scale), cvRound(image.cols/scale), CV_8UC1 );
    //cv::Mat imgCopy( 732*0.8, 1100*0.8, CV_8UC1 );
    //Size( std::min (image.rows, 100), std::min(image.cols, 100) )
    cv::Mat imgGray;
    cv::cvtColor( image, imgGray, cv::COLOR_BGR2GRAY );
    cv::resize( imgGray, imgCopy, imgCopy.size()  , 0, 0, cv::INTER_LINEAR );
    cv::equalizeHist( imgCopy, imgCopy );

    vector<cv::Rect> faces;
    cascade.detectMultiScale( imgCopy, faces,
        1.1, 2, 0
        //|cv::CASCADE_FIND_BIGGEST_OBJECT
        //|cv::CASCADE_DO_ROUGH_SEARCH
        |cv::CASCADE_SCALE_IMAGE
        ,
        cv::Size(11, 11) );
    if( tryflip )
    {
        vector<cv::Rect> faces_fliped;
        cv::flip(imgCopy, imgCopy, 1);
        cascade.detectMultiScale( imgCopy, faces_fliped,
         1.1, 2, 0
            //|cv::CASCADE_FIND_BIGGEST_OBJECT
            //|cv::CASCADE_DO_ROUGH_SEARCH
         |cv::CASCADE_SCALE_IMAGE
         ,
         cv::Size(17, 17) );

        faces.insert(faces.end(), faces_fliped.begin(), faces_fliped.end());
    }

    cout << "Number of faces: " << faces.size() << endl;

    return faces;
}
<|endoftext|>


<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed-drivers/mbed.h"
#include "ble/BLE.h"
#include "EddystoneService.h"

#include "PersistentStorageHelper/ConfigParamsPersistence.h"
// #include "stdio.h"

// Instantiation of the main event loop for this program

#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
#include "EventQueue/EventQueueMinar.h"
typedef eq::EventQueueMinar event_queue_t;

#else      // otherwise use the event classic queue
#include "EventQueue/EventQueueClassic.h"
typedef eq::EventQueueClassic<
    /* event count */ 10
> event_queue_t;

#endif

static event_queue_t eventQueue;

EddystoneService *eddyServicePtr;

/* Duration after power-on that config service is available. */
static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = YOTTA_CFG_EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS;

/* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */
static const PowerLevels_t advTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS;
/* Values for radio power levels, provided by manufacturer. */
static const PowerLevels_t radioTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS;

// This allows a quick switch between targets without changing the 'platform'
// settings in config.json each time. If you do change target to nrf51dk-gcc,
// note you will still need to change 'softdevice' to 's130'
//
 #define QUICK_SWITCH_TO_NRF51DK 1
#ifdef QUICK_SWITCH_TO_NRF51DK
    #define LED_OFF 1
    #define CONFIG_LED LED3
    #define SHUTDOWN_LED LED1
    #define RESET_BUTTON BUTTON1
#else
    #define LED_OFF YOTTA_CFG_PLATFORM_LED_OFF
    #define CONFIG_LED YOTTA_CFG_PLATFORM_CONFIG_LED
    #define SHUTDOWN_LED YOTTA_CFG_PLATFORM_SHUTDOWN_LED
    #define RESET_BUTTON YOTTA_CFG_PLATFORM_RESET_BUTTON
#endif

DigitalOut configLED(CONFIG_LED, LED_OFF);
DigitalOut shutdownLED(SHUTDOWN_LED, LED_OFF);
InterruptIn button(RESET_BUTTON);

static int buttonBusy;                                    // semaphore to make prevent switch bounce problems

static const int BLINKY_MSEC = 500;                       // How long to cycle config LED on/off
static int beaconIsOn = 1;                                // Button handler boolean to switch on or off
static event_queue_t::event_handle_t handle = 0;         // For the config mode timeout
static event_queue_t::event_handle_t BlinkyHandle = 0;   // For the blinking LED when in config mode

static void blinky(void)  { configLED = !configLED; }
static void shutdownLED_on(void) { shutdownLED = !LED_OFF; }
static void shutdownLED_off(void) { shutdownLED = LED_OFF; }
static void freeButtonBusy(void) { buttonBusy = false; }

static void configLED_on(void) {
    configLED = !LED_OFF;
    BlinkyHandle = eventQueue.post_every(blinky, BLINKY_MSEC);
}
static void configLED_off(void) {
    configLED = LED_OFF;
    if (BlinkyHandle) {
        eventQueue.cancel(BlinkyHandle);
        BlinkyHandle = NULL;
    }
}

/**
 * Callback triggered some time after application started to switch to beacon mode.
 */
static void timeoutToStartEddystoneBeaconAdvertisements(void)
{
    Gap::GapState_t state;
    state = BLE::Instance().gap().getState();
    if (!state.connected) { /* don't switch if we're in a connected state. */
        eddyServicePtr->startEddystoneBeaconAdvertisements();
        configLED_off();
    }
}

/**
 * Callback triggered for a connection event.
 */
static void connectionCallback(const Gap::ConnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    // Stop advertising whatever the current mode
    eddyServicePtr->stopEddystoneBeaconAdvertisements();
}

/**
 * Callback triggered for a disconnection event.
 */
static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    BLE::Instance().gap().startAdvertising();
    // Save params in persistent storage
    EddystoneService::EddystoneParams_t params;
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);
    // Ensure LED is off at the end of Config Mode or during a connection
    configLED_off();
    // 0.5 Second callback to rapidly re-establish Beaconing Service
    // (because it needs to be executed outside of disconnect callback)
    eventQueue.post_in(timeoutToStartEddystoneBeaconAdvertisements, 500 /* ms */);
}

// Callback used to handle button presses from thread mode (not IRQ)
static void button_task(void) {
    eventQueue.cancel(handle);   // kill any pending callback tasks

    if (beaconIsOn) {
        beaconIsOn = 0;
        eddyServicePtr->stopEddystoneBeaconAdvertisements();
        configLED_off();    // just in case it's still running...
        shutdownLED_on();   // Flash shutdownLED to let user know we're turning off
        eventQueue.post_in(shutdownLED_off, 1000);
    } else {

        beaconIsOn = 1;
        eddyServicePtr->startEddystoneConfigAdvertisements();
        configLED_on();
        handle = eventQueue.post_in(
            timeoutToStartEddystoneBeaconAdvertisements,
            CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
        );
    }
    eventQueue.post_in(freeButtonBusy, 750 /* ms */);
}

/**
 * Raw IRQ handler for the reset button. We don't want to actually do any work here.
 * Instead, we queue work to happen later using an event queue, by posting a callback.
 * This has the added avantage of serialising actions, so if the button press happens
 * during the config->beacon mode transition timeout, the button_task won't happen
 * until the previous task has finished.
 *
 * If your buttons aren't debounced, you should do this in software, or button_task
 * might get queued multiple times.
 */
static void reset_rise(void)
{
    if (!buttonBusy) {
        buttonBusy = true;
        eventQueue.post(button_task);
    }
}

static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext)
{
    /* Initialization error handling goes here... */
    (void) initContext;
}

static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
{
    BLE         &ble  = initContext->ble;
    ble_error_t error = initContext->error;

    if (error != BLE_ERROR_NONE) {
        onBleInitError(initContext);
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    ble.gap().onConnection(connectionCallback);

    EddystoneService::EddystoneParams_t params;

    // Determine if booting directly after re-Flash or not
    if (loadEddystoneServiceConfigParams(&params)) {
        // 2+ Boot after reflash, so get parms from Persistent Storage
        eddyServicePtr = new EddystoneService(ble, params, radioTxPowerLevels, eventQueue);
    } else {
        // 1st Boot after reflash, so reset everything to defaults
        /* NOTE: slots are initialized in the constructor from the config.json file */
        eddyServicePtr = new EddystoneService(ble, advTxPowerLevels, radioTxPowerLevels, eventQueue);
    }

    // Save Default params in persistent storage ready for next boot event
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);

    // Start the Eddystone Config service - This will never stop (only connectability will change)
    eddyServicePtr->startEddystoneConfigService();

    /* Start Eddystone config Advertizements (to initialize everything properly) */
    configLED_on();
    eddyServicePtr->startEddystoneConfigAdvertisements();
    handle = eventQueue.post_in(
        timeoutToStartEddystoneBeaconAdvertisements,
        CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
    );

   // now shut everything off (used for final beacon that ships w/ battery)
   eventQueue.post_in(button_task, 2000 /* ms */);
}

void app_start(int, char *[])
{
    /* Tell standard C library to not allocate large buffers for these streams */
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    setbuf(stdin, NULL);

    beaconIsOn = 1;             // Booting up, initialize for button handler
    buttonBusy = false;         // software debouncing of the reset button
    button.rise(&reset_rise);   // setup reset button

    BLE &ble = BLE::Instance();
    ble.init(bleInitComplete);
}

#if !defined(YOTTA_CFG_MBED_OS)

int main() {

    app_start(0, NULL);

    while (true) {
       eventQueue.dispatch();
       ble.waitForEvent();
    }

    return 0;
}

#endif
<commit_msg>Fix reference to BLE instance.<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed-drivers/mbed.h"
#include "ble/BLE.h"
#include "EddystoneService.h"

#include "PersistentStorageHelper/ConfigParamsPersistence.h"
// #include "stdio.h"

// Instantiation of the main event loop for this program

#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
#include "EventQueue/EventQueueMinar.h"
typedef eq::EventQueueMinar event_queue_t;

#else      // otherwise use the event classic queue
#include "EventQueue/EventQueueClassic.h"
typedef eq::EventQueueClassic<
    /* event count */ 10
> event_queue_t;

#endif

static event_queue_t eventQueue;

EddystoneService *eddyServicePtr;

/* Duration after power-on that config service is available. */
static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = YOTTA_CFG_EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS;

/* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */
static const PowerLevels_t advTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS;
/* Values for radio power levels, provided by manufacturer. */
static const PowerLevels_t radioTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS;

// This allows a quick switch between targets without changing the 'platform'
// settings in config.json each time. If you do change target to nrf51dk-gcc,
// note you will still need to change 'softdevice' to 's130'
//
 #define QUICK_SWITCH_TO_NRF51DK 1
#ifdef QUICK_SWITCH_TO_NRF51DK
    #define LED_OFF 1
    #define CONFIG_LED LED3
    #define SHUTDOWN_LED LED1
    #define RESET_BUTTON BUTTON1
#else
    #define LED_OFF YOTTA_CFG_PLATFORM_LED_OFF
    #define CONFIG_LED YOTTA_CFG_PLATFORM_CONFIG_LED
    #define SHUTDOWN_LED YOTTA_CFG_PLATFORM_SHUTDOWN_LED
    #define RESET_BUTTON YOTTA_CFG_PLATFORM_RESET_BUTTON
#endif

DigitalOut configLED(CONFIG_LED, LED_OFF);
DigitalOut shutdownLED(SHUTDOWN_LED, LED_OFF);
InterruptIn button(RESET_BUTTON);

static int buttonBusy;                                    // semaphore to make prevent switch bounce problems

static const int BLINKY_MSEC = 500;                       // How long to cycle config LED on/off
static int beaconIsOn = 1;                                // Button handler boolean to switch on or off
static event_queue_t::event_handle_t handle = 0;         // For the config mode timeout
static event_queue_t::event_handle_t BlinkyHandle = 0;   // For the blinking LED when in config mode

static void blinky(void)  { configLED = !configLED; }
static void shutdownLED_on(void) { shutdownLED = !LED_OFF; }
static void shutdownLED_off(void) { shutdownLED = LED_OFF; }
static void freeButtonBusy(void) { buttonBusy = false; }

static void configLED_on(void) {
    configLED = !LED_OFF;
    BlinkyHandle = eventQueue.post_every(blinky, BLINKY_MSEC);
}
static void configLED_off(void) {
    configLED = LED_OFF;
    if (BlinkyHandle) {
        eventQueue.cancel(BlinkyHandle);
        BlinkyHandle = NULL;
    }
}

/**
 * Callback triggered some time after application started to switch to beacon mode.
 */
static void timeoutToStartEddystoneBeaconAdvertisements(void)
{
    Gap::GapState_t state;
    state = BLE::Instance().gap().getState();
    if (!state.connected) { /* don't switch if we're in a connected state. */
        eddyServicePtr->startEddystoneBeaconAdvertisements();
        configLED_off();
    }
}

/**
 * Callback triggered for a connection event.
 */
static void connectionCallback(const Gap::ConnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    // Stop advertising whatever the current mode
    eddyServicePtr->stopEddystoneBeaconAdvertisements();
}

/**
 * Callback triggered for a disconnection event.
 */
static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    BLE::Instance().gap().startAdvertising();
    // Save params in persistent storage
    EddystoneService::EddystoneParams_t params;
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);
    // Ensure LED is off at the end of Config Mode or during a connection
    configLED_off();
    // 0.5 Second callback to rapidly re-establish Beaconing Service
    // (because it needs to be executed outside of disconnect callback)
    eventQueue.post_in(timeoutToStartEddystoneBeaconAdvertisements, 500 /* ms */);
}

// Callback used to handle button presses from thread mode (not IRQ)
static void button_task(void) {
    eventQueue.cancel(handle);   // kill any pending callback tasks

    if (beaconIsOn) {
        beaconIsOn = 0;
        eddyServicePtr->stopEddystoneBeaconAdvertisements();
        configLED_off();    // just in case it's still running...
        shutdownLED_on();   // Flash shutdownLED to let user know we're turning off
        eventQueue.post_in(shutdownLED_off, 1000);
    } else {

        beaconIsOn = 1;
        eddyServicePtr->startEddystoneConfigAdvertisements();
        configLED_on();
        handle = eventQueue.post_in(
            timeoutToStartEddystoneBeaconAdvertisements,
            CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
        );
    }
    eventQueue.post_in(freeButtonBusy, 750 /* ms */);
}

/**
 * Raw IRQ handler for the reset button. We don't want to actually do any work here.
 * Instead, we queue work to happen later using an event queue, by posting a callback.
 * This has the added avantage of serialising actions, so if the button press happens
 * during the config->beacon mode transition timeout, the button_task won't happen
 * until the previous task has finished.
 *
 * If your buttons aren't debounced, you should do this in software, or button_task
 * might get queued multiple times.
 */
static void reset_rise(void)
{
    if (!buttonBusy) {
        buttonBusy = true;
        eventQueue.post(button_task);
    }
}

static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext)
{
    /* Initialization error handling goes here... */
    (void) initContext;
}

static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
{
    BLE         &ble  = initContext->ble;
    ble_error_t error = initContext->error;

    if (error != BLE_ERROR_NONE) {
        onBleInitError(initContext);
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    ble.gap().onConnection(connectionCallback);

    EddystoneService::EddystoneParams_t params;

    // Determine if booting directly after re-Flash or not
    if (loadEddystoneServiceConfigParams(&params)) {
        // 2+ Boot after reflash, so get parms from Persistent Storage
        eddyServicePtr = new EddystoneService(ble, params, radioTxPowerLevels, eventQueue);
    } else {
        // 1st Boot after reflash, so reset everything to defaults
        /* NOTE: slots are initialized in the constructor from the config.json file */
        eddyServicePtr = new EddystoneService(ble, advTxPowerLevels, radioTxPowerLevels, eventQueue);
    }

    // Save Default params in persistent storage ready for next boot event
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);

    // Start the Eddystone Config service - This will never stop (only connectability will change)
    eddyServicePtr->startEddystoneConfigService();

    /* Start Eddystone config Advertizements (to initialize everything properly) */
    configLED_on();
    eddyServicePtr->startEddystoneConfigAdvertisements();
    handle = eventQueue.post_in(
        timeoutToStartEddystoneBeaconAdvertisements,
        CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
    );

   // now shut everything off (used for final beacon that ships w/ battery)
   eventQueue.post_in(button_task, 2000 /* ms */);
}

void app_start(int, char *[])
{
    /* Tell standard C library to not allocate large buffers for these streams */
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    setbuf(stdin, NULL);

    beaconIsOn = 1;             // Booting up, initialize for button handler
    buttonBusy = false;         // software debouncing of the reset button
    button.rise(&reset_rise);   // setup reset button

    BLE &ble = BLE::Instance();
    ble.init(bleInitComplete);
}

#if !defined(YOTTA_CFG_MBED_OS)

int main() {

    app_start(0, NULL);

    while (true) {
       eventQueue.dispatch();
       BLE::Instance().waitForEvent();
    }

    return 0;
}

#endif
<|endoftext|>