<commit_before>#pragma once

#include <glkernel/sample.h>

#include <cassert>
#include <random>
#include <vector>
#include <array>
#include <list>
#include <iterator>
#include <tuple>
#include <algorithm>

#include <glkernel/glm_compatability.h>

namespace glkernel
{

namespace sample
{

// optimization grid for identifying adjacent points

template <typename T, glm::precision P>
struct poisson_square_map
{
    poisson_square_map(const T min_dist)
    : m_none{ static_cast<size_t>(-1) }
    , m_side{ static_cast<size_t>(std::ceil(sqrt(2.0) / min_dist)) }
    , m_dist2(min_dist * min_dist)
    {
        m_mask.resize(m_side * m_side, m_none);
    }

    void mask(const glm::tvec2<T, P> & point, const size_t k)
    {
        const auto s = static_cast<int>(m_side);
        const auto o = static_cast<int>(point.y * s) * s + static_cast<int>(point.x * s);

        assert(m_mask[o] == m_none);

        m_mask[o] = k;
    }

    bool masked(const glm::tvec2<T, P> & probe, const tkernel<glm::tvec2<T, P>> & kernel) const
    {
        const auto s = static_cast<int>(m_side);

        const auto x = static_cast<int>(probe.x * s);
        const auto y = static_cast<int>(probe.y * s);

        const auto corners = std::array<int, 4>{ { y - 2, x - 2, y + 2, x + 2 } };

        for (int j = y - 2; j < y + 3; ++j)
            for (int i = x - 2; i < x + 3; ++i)
            {
                // optimization: skip the 4 corner cases, since the fall not within distance anyway ...
                if ((j == corners[0] || j == corners[2]) && (i == corners[1] || i == corners[3]))
                    continue;

                const auto i_tiled = i < 0 ? i + s : i % s;
                const auto j_tiled = j < 0 ? j + s : j % s;

                const auto o = m_mask[j_tiled * s + i_tiled];
                if (o == m_none)
                    continue;

                auto masking_probe = kernel[o];

                if (i < 0)
                    masking_probe.x -= 1.0;
                else if (i >= s)
                    masking_probe.x += 1.0;

                if (j < 0)
                    masking_probe.y -= 1.0;
                else if (j >= s)
                    masking_probe.y += 1.0;

                // also optimized by using square distance->skipping sqrt
                const auto delta = masking_probe - probe;
                if (glm::dot(delta, delta) < m_dist2)
                    return true;
            }

        return false;
    }

protected:
    size_t m_none;

    size_t m_side;
    T m_dist2;

    std::vector<size_t> m_mask;
};

template <typename T, glm::precision P>
size_t poisson_square(tkernel<glm::tvec2<T, P>> & kernel, const unsigned int num_probes)
{
    assert(kernel.depth() == 1);

    const T min_dist = 1 / sqrt(static_cast<T>(kernel.size() * sqrt(2)));
    return poisson_square(kernel, min_dist, num_probes);
}

template <typename T, glm::precision P>
size_t poisson_square(tkernel<glm::tvec2<T, P>> & kernel, const T min_dist, const unsigned int num_probes)
{
    assert(kernel.depth() == 1);

    std::random_device RD;
    std::mt19937_64 generator(RD());

    std::uniform_real_distribution<> radius_dist(min_dist, min_dist * 2.0);
    std::uniform_real_distribution<> angle_dist(0.0, 2.0 * glm::pi<T>());

    std::uniform_int_distribution<> int_distribute(0, std::numeric_limits<int>::max());

    auto occupancy = poisson_square_map<T, P>{ min_dist };

    size_t k = 0; // number of valid/final points within the kernel
    kernel[k] = glm::tvec2<T, P>(0.5, 0.5);

    auto actives = std::list<size_t>();
    actives.push_back(k);

    occupancy.mask(kernel[k], k);

    while (!actives.empty() && k < kernel.size() - 1)
    {
        // randomly pick an active point
        const auto pick = int_distribute(generator);

        auto pick_it = actives.begin();
        std::advance(pick_it, pick % actives.size());

        const auto active = kernel[*pick_it];

        std::vector<std::tuple<glm::tvec2<T, P>, T>> probes{ num_probes };

        #pragma omp parallel for
        for (int i = 0; i < static_cast<int>(num_probes); ++i)
        {
            const auto r = radius_dist(generator);
            const auto a = angle_dist(generator);

            auto probe = glm::tvec2<T, P>{ active.x + r * cos(a), active.y + r * sin(a) };

            // within square? (tilable)
            if (probe.x < 0.0)
                probe.x += 1.0;
            else if (probe.x >= 1.0)
                probe.x -= 1.0;

            if (probe.y < 0.0)
                probe.y += 1.0;
            else if (probe.y >= 1.0)
                probe.y -= 1.0;

            // Note: do NOT make this optimization
            //if (!tilable && (probe.x < 0.0 || probe.x > 1.0 || probe.y < 0.0 || probe.y > 1.0))
            //    continue;

            // points within min_dist?
            const auto masked = occupancy.masked(probe, kernel);
            const auto delta = abs(active - probe);

            probes[i] = std::make_tuple<glm::tvec2<T, P>, T>(std::move(probe), (masked ? static_cast<T>(-1.0) : glm::dot(delta, delta)));
        }

        // pick nearest probe from sample set
        glm::vec2 nearest_probe;
        auto nearest_dist = 4 * min_dist * min_dist;
        auto nearest_found = false;

        for (int i = 0; i < static_cast<int>(num_probes); ++i)
        {
            // is this nearest point yet? - optimized by using square distance -> skipping sqrt
            const auto new_dist = std::get<1>(probes[i]);
            if (new_dist < 0.0 || nearest_dist < new_dist)
                continue;

            if (!nearest_found)
                nearest_found = true;

            nearest_dist = new_dist;
            nearest_probe = std::get<0>(probes[i]);
        }

        if (!nearest_found && (actives.size() > 0 || k > 1))
        {
            actives.erase(pick_it);
            continue;
        }

        kernel[++k] = nearest_probe;
        actives.push_back(k);

        occupancy.mask(nearest_probe, k);
    }

    return k + 1;
}

template <typename T, glm::precision P>
size_t multi_jittered(tkernel<glm::tvec2<T, P>> & kernel)
{
    assert(kernel.depth() == 1);

    std::random_device RD;
    std::mt19937_64 generator(RD());

    auto stratum_size = 1.0 / (kernel.width() * kernel.height());
    auto subcell_width = 1.0 / kernel.width();
    auto subcell_height = 1.0 / kernel.height();

    std::uniform_real_distribution<> jitter_dist(0.0, stratum_size);

    std::vector<std::pair<int, int>> pool;
    // reverse height and width inside subcells
    for (auto x = 0; x < kernel.height(); x++)
    {
        for (auto y = 0; y < kernel.width(); y++)
        {
            pool.push_back({ x, y });
        }
    }
    std::random_shuffle(pool.begin(), pool.end());

    size_t k = 0;
    for (auto x = 0; x < kernel.width(); x++)
    {
        for (auto y = 0; y < kernel.height(); y++)
        {
            auto x_coord = x * subcell_width  + pool[k].first  * stratum_size + jitter_dist(generator);
            auto y_coord = y * subcell_height + pool[k].second * stratum_size + jitter_dist(generator);
            auto sample = glm::tvec2<T, P>(x_coord, y_coord);
            kernel[k++] = sample;
        }
    }

    return k;
}

} // namespace sample

} // namespace glkernel
<commit_msg>Use pre-increment in loops<commit_after>#pragma once

#include <glkernel/sample.h>

#include <cassert>
#include <random>
#include <vector>
#include <array>
#include <list>
#include <iterator>
#include <tuple>
#include <algorithm>

#include <glkernel/glm_compatability.h>

namespace glkernel
{

namespace sample
{

// optimization grid for identifying adjacent points

template <typename T, glm::precision P>
struct poisson_square_map
{
    poisson_square_map(const T min_dist)
    : m_none{ static_cast<size_t>(-1) }
    , m_side{ static_cast<size_t>(std::ceil(sqrt(2.0) / min_dist)) }
    , m_dist2(min_dist * min_dist)
    {
        m_mask.resize(m_side * m_side, m_none);
    }

    void mask(const glm::tvec2<T, P> & point, const size_t k)
    {
        const auto s = static_cast<int>(m_side);
        const auto o = static_cast<int>(point.y * s) * s + static_cast<int>(point.x * s);

        assert(m_mask[o] == m_none);

        m_mask[o] = k;
    }

    bool masked(const glm::tvec2<T, P> & probe, const tkernel<glm::tvec2<T, P>> & kernel) const
    {
        const auto s = static_cast<int>(m_side);

        const auto x = static_cast<int>(probe.x * s);
        const auto y = static_cast<int>(probe.y * s);

        const auto corners = std::array<int, 4>{ { y - 2, x - 2, y + 2, x + 2 } };

        for (int j = y - 2; j < y + 3; ++j)
            for (int i = x - 2; i < x + 3; ++i)
            {
                // optimization: skip the 4 corner cases, since the fall not within distance anyway ...
                if ((j == corners[0] || j == corners[2]) && (i == corners[1] || i == corners[3]))
                    continue;

                const auto i_tiled = i < 0 ? i + s : i % s;
                const auto j_tiled = j < 0 ? j + s : j % s;

                const auto o = m_mask[j_tiled * s + i_tiled];
                if (o == m_none)
                    continue;

                auto masking_probe = kernel[o];

                if (i < 0)
                    masking_probe.x -= 1.0;
                else if (i >= s)
                    masking_probe.x += 1.0;

                if (j < 0)
                    masking_probe.y -= 1.0;
                else if (j >= s)
                    masking_probe.y += 1.0;

                // also optimized by using square distance->skipping sqrt
                const auto delta = masking_probe - probe;
                if (glm::dot(delta, delta) < m_dist2)
                    return true;
            }

        return false;
    }

protected:
    size_t m_none;

    size_t m_side;
    T m_dist2;

    std::vector<size_t> m_mask;
};

template <typename T, glm::precision P>
size_t poisson_square(tkernel<glm::tvec2<T, P>> & kernel, const unsigned int num_probes)
{
    assert(kernel.depth() == 1);

    const T min_dist = 1 / sqrt(static_cast<T>(kernel.size() * sqrt(2)));
    return poisson_square(kernel, min_dist, num_probes);
}

template <typename T, glm::precision P>
size_t poisson_square(tkernel<glm::tvec2<T, P>> & kernel, const T min_dist, const unsigned int num_probes)
{
    assert(kernel.depth() == 1);

    std::random_device RD;
    std::mt19937_64 generator(RD());

    std::uniform_real_distribution<> radius_dist(min_dist, min_dist * 2.0);
    std::uniform_real_distribution<> angle_dist(0.0, 2.0 * glm::pi<T>());

    std::uniform_int_distribution<> int_distribute(0, std::numeric_limits<int>::max());

    auto occupancy = poisson_square_map<T, P>{ min_dist };

    size_t k = 0; // number of valid/final points within the kernel
    kernel[k] = glm::tvec2<T, P>(0.5, 0.5);

    auto actives = std::list<size_t>();
    actives.push_back(k);

    occupancy.mask(kernel[k], k);

    while (!actives.empty() && k < kernel.size() - 1)
    {
        // randomly pick an active point
        const auto pick = int_distribute(generator);

        auto pick_it = actives.begin();
        std::advance(pick_it, pick % actives.size());

        const auto active = kernel[*pick_it];

        std::vector<std::tuple<glm::tvec2<T, P>, T>> probes{ num_probes };

        #pragma omp parallel for
        for (int i = 0; i < static_cast<int>(num_probes); ++i)
        {
            const auto r = radius_dist(generator);
            const auto a = angle_dist(generator);

            auto probe = glm::tvec2<T, P>{ active.x + r * cos(a), active.y + r * sin(a) };

            // within square? (tilable)
            if (probe.x < 0.0)
                probe.x += 1.0;
            else if (probe.x >= 1.0)
                probe.x -= 1.0;

            if (probe.y < 0.0)
                probe.y += 1.0;
            else if (probe.y >= 1.0)
                probe.y -= 1.0;

            // Note: do NOT make this optimization
            //if (!tilable && (probe.x < 0.0 || probe.x > 1.0 || probe.y < 0.0 || probe.y > 1.0))
            //    continue;

            // points within min_dist?
            const auto masked = occupancy.masked(probe, kernel);
            const auto delta = abs(active - probe);

            probes[i] = std::make_tuple<glm::tvec2<T, P>, T>(std::move(probe), (masked ? static_cast<T>(-1.0) : glm::dot(delta, delta)));
        }

        // pick nearest probe from sample set
        glm::vec2 nearest_probe;
        auto nearest_dist = 4 * min_dist * min_dist;
        auto nearest_found = false;

        for (int i = 0; i < static_cast<int>(num_probes); ++i)
        {
            // is this nearest point yet? - optimized by using square distance -> skipping sqrt
            const auto new_dist = std::get<1>(probes[i]);
            if (new_dist < 0.0 || nearest_dist < new_dist)
                continue;

            if (!nearest_found)
                nearest_found = true;

            nearest_dist = new_dist;
            nearest_probe = std::get<0>(probes[i]);
        }

        if (!nearest_found && (actives.size() > 0 || k > 1))
        {
            actives.erase(pick_it);
            continue;
        }

        kernel[++k] = nearest_probe;
        actives.push_back(k);

        occupancy.mask(nearest_probe, k);
    }

    return k + 1;
}

template <typename T, glm::precision P>
size_t multi_jittered(tkernel<glm::tvec2<T, P>> & kernel)
{
    assert(kernel.depth() == 1);

    std::random_device RD;
    std::mt19937_64 generator(RD());

    auto stratum_size = 1.0 / (kernel.width() * kernel.height());
    auto subcell_width = 1.0 / kernel.width();
    auto subcell_height = 1.0 / kernel.height();

    std::uniform_real_distribution<> jitter_dist(0.0, stratum_size);

    std::vector<std::pair<int, int>> pool;
    // reverse height and width inside subcells
    for (auto x = 0; x < kernel.height(); ++x)
    {
        for (auto y = 0; y < kernel.width(); ++y)
        {
            pool.push_back({ x, y });
        }
    }
    std::random_shuffle(pool.begin(), pool.end());

    size_t k = 0;
    for (auto x = 0; x < kernel.width(); ++x)
    {
        for (auto y = 0; y < kernel.height(); ++y)
        {
            auto x_coord = x * subcell_width  + pool[k].first  * stratum_size + jitter_dist(generator);
            auto y_coord = y * subcell_height + pool[k].second * stratum_size + jitter_dist(generator);
            auto sample = glm::tvec2<T, P>(x_coord, y_coord);
            kernel[k++] = sample;
        }
    }

    return k;
}

} // namespace sample

} // namespace glkernel
<|endoftext|>


<commit_before>#include <albert/scraper.hpp>

#include <iostream>
#include <deque>
#include <fstream>
#include <boost/locale.hpp>

#include <albert/util.hpp>
#include <albert/interpreter.hpp>

namespace supermarx
{
	static const std::string domain_uri = "http://www.ah.nl";
	static const std::string rest_uri = domain_uri + "/service/rest";

	scraper::scraper(product_callback_t _product_callback, tag_hierarchy_callback_t _tag_hierarchy_callback, unsigned int _ratelimit, bool _cache, bool _register_tags)
	: product_callback(_product_callback)
	, tag_hierarchy_callback(_tag_hierarchy_callback)
	, dl("supermarx albert/1.2", _ratelimit, _cache ? boost::optional<std::string>("./cache") : boost::none)
	, m(dl, [&]() { error_count++; })
	, register_tags(_register_tags)
	, todo()
	, blacklist()
	, tag_hierarchy()
	, product_count(0)
	, page_count(0)
	, error_count(0)
	{}

	Json::Value scraper::parse(std::string const& uri, std::string const& body)
	{
		Json::Value root;
		Json::Reader reader;

		if(!body.empty() && !reader.parse(body, root, false))
		{
			dl.clear(uri);
			throw std::runtime_error("Could not parse json feed");
		}

		return root;
	}

	Json::Value scraper::download(std::string const& uri)
	{
		return stubborn::attempt<Json::Value>([&](){
			return parse(uri, dl.fetch(uri).body);
		});
	}

	bool scraper::is_blacklisted(std::string const& uri)
	{
		if(!blacklist.insert(uri).second) // Already visited uri
			return true;

		if(uri.find("%2F") != std::string::npos) // Bug in AH server, will get 404
			return true;

		if(uri.find("merk=100%") != std::string::npos) // Ditto
			return true;

		return false;
	}

	void scraper::order(page_t const& p)
	{
		if(is_blacklisted(p.uri))
			return;

		m.schedule(p.uri, [&, p](downloader::response const& response) {
			process(p, response);
		});
	}

	void scraper::process(const page_t &current_page, const downloader::response &response)
	{
		page_count++;

		/* Two modes:
		 * - register_tags, fetches all products via the "Filters", goes through them in-order.
		 * - !register_tags, fetches all products via inline ProductLanes and SeeMore widgets
		 * The first takes an order more time than the second.
		 * The first actually maps all categories and tags, which do not change often.
		 * I suggest you run a scrape with this tag at most once a week.
		 * Use sparingly.
		 */
		Json::Value cat_root(parse(current_page.uri, response.body));
		for(auto const& lane : cat_root["_embedded"]["lanes"])
		{
			if(register_tags && lane["id"].asString() == "Filters" && current_page.expand)
			{
				// Only process filters exhaustively if register_tags is enabled
				parse_filterlane(lane, current_page);
			}
			else if(lane["type"].asString() == "ProductLane")
			{
				parse_productlane(lane, current_page);
			}
			else if(!register_tags && lane["type"].asString() == "SeeMoreLane")
			{
				parse_seemorelane(lane, current_page);
			}
		}
	}

	void scraper::add_tag_to_hierarchy_f(std::vector<message::tag> const& _parent_tags, message::tag const& current_tag)
	{
		if(current_tag.category != "Soort")
			return; // Other categories do not possess an hierarchy.

		std::vector<message::tag> parent_tags(_parent_tags.size());
		std::reverse_copy(std::begin(_parent_tags), std::end(_parent_tags), std::begin(parent_tags));
		auto parent_it = std::find_if(std::begin(parent_tags), std::end(parent_tags), [&](message::tag const& t){
			return t.category == current_tag.category;
		});

		if(parent_it == std::end(parent_tags))
			return; // Do not add

		message::tag const& parent_tag = *parent_it;

		auto hierarchy_it(tag_hierarchy.find(parent_tag));
		if(hierarchy_it == std::end(tag_hierarchy))
			tag_hierarchy.emplace(parent_tag, std::set<message::tag>({ current_tag }));
		else
		{
			if(!hierarchy_it->second.emplace(current_tag).second)
				return;
		}

		// Emit hierarchy finding
		tag_hierarchy_callback(parent_tag, current_tag);
	}

	void scraper::parse_filterlane(Json::Value const& lane, page_t const& current_page)
	{
		for(auto const& filter_bar : lane["_embedded"]["items"])
		{
			if(filter_bar["resourceType"].asString() != "FilterBar")
				std::runtime_error("Unexpected element under Filters");

			for(auto const& filter : filter_bar["_embedded"]["filters"])
			{
				std::string filter_label = filter["label"].asString();
				for(auto const& cat : filter["_embedded"]["filterItems"])
				{
					std::string uri = cat["navItem"]["link"]["href"].asString();
					std::string title = cat["label"].asString();
					remove_hyphens(title);

					message::tag tag({title, filter_label});
					add_tag_to_hierarchy_f(current_page.tags, tag);

					std::vector<message::tag> tags;
					tags.insert(tags.end(), current_page.tags.begin(), current_page.tags.end());
					tags.push_back(tag);

					order({rest_uri + uri, title, true, tags});
				}

				break; // Only process first in bar, until none are left. (will fetch everything eventually)
			}
		}
	}

	void scraper::parse_productlane(Json::Value const& lane, page_t const& current_page)
	{
		std::string lane_name = lane["id"].asString();

		std::vector<message::tag> tags;
		tags.insert(tags.end(), current_page.tags.begin(), current_page.tags.end());
		tags.push_back({lane_name, std::string("Soort")});

		for(auto const& lane_item : lane["_embedded"]["items"])
		{
			std::string lane_type = lane_item["type"].asString();
			if(lane_type == "Product")
			{
				auto const& product = lane_item["_embedded"]["productCard"]["_embedded"]["product"];
				interpreter::interpret(product, current_page, product_callback);
				product_count++;
			}
			else if(!register_tags && lane_type == "SeeMore")
			{
				if(lane_item["navItem"]["link"]["pageType"] == "legacy") // Old-style page in SeeMore Editorial
					continue;

				order({rest_uri + lane_item["navItem"]["link"]["href"].asString(), lane_name, true, tags});
			}
		}
	}

	void scraper::parse_seemorelane(Json::Value const& lane, page_t const& current_page)
	{
		for(auto const& lane_item : lane["_embedded"]["items"])
		{
			std::string title = lane_item["text"]["title"].asString();
			remove_hyphens(title);
			std::string uri = lane_item["navItem"]["link"]["href"].asString();

			std::vector<message::tag> tags;
			tags.insert(tags.end(), current_page.tags.begin(), current_page.tags.end());
			tags.push_back({title, std::string("Soort")});

			order({rest_uri + uri, title, true, tags});
		}
	}

	void scraper::scrape()
	{
		product_count = 0;
		page_count = 0;
		error_count = 0;

		Json::Value producten_root(download(rest_uri + "/producten"));

		for(auto const& lane : producten_root["_embedded"]["lanes"])
		{
			if(lane["id"].asString() != "productCategoryNavigation")
				continue;

			for(auto const& cat : lane["_embedded"]["items"])
			{
				std::string title = cat["title"].asString();
				std::string uri = cat["navItem"]["link"]["href"].asString();

				remove_hyphens(title);

				order({rest_uri + uri, title, true, {message::tag{title, std::string("Soort")}}});
			}
		}

		m.process_all();
		std::cerr << "Pages: " << page_count << ", products: " << product_count << ", errors: " << error_count << std::endl;
	}

	raw scraper::download_image(const std::string& uri)
	{
		std::string buf(dl.fetch(uri).body);
		return raw(buf.data(), buf.length());
	}
}
<commit_msg>Updated product<commit_after>#include <albert/scraper.hpp>

#include <iostream>
#include <deque>
#include <fstream>
#include <boost/locale.hpp>

#include <albert/util.hpp>
#include <albert/interpreter.hpp>

namespace supermarx
{
	static const std::string domain_uri = "http://www.ah.nl";
	static const std::string rest_uri = domain_uri + "/service/rest";

	scraper::scraper(product_callback_t _product_callback, tag_hierarchy_callback_t _tag_hierarchy_callback, unsigned int _ratelimit, bool _cache, bool _register_tags)
	: product_callback(_product_callback)
	, tag_hierarchy_callback(_tag_hierarchy_callback)
	, dl("supermarx albert/1.2", _ratelimit, _cache ? boost::optional<std::string>("./cache") : boost::none)
	, m(dl, [&]() { error_count++; })
	, register_tags(_register_tags)
	, todo()
	, blacklist()
	, tag_hierarchy()
	, product_count(0)
	, page_count(0)
	, error_count(0)
	{}

	Json::Value scraper::parse(std::string const& uri, std::string const& body)
	{
		Json::Value root;
		Json::Reader reader;

		if(!body.empty() && !reader.parse(body, root, false))
		{
			dl.clear(uri);
			throw std::runtime_error("Could not parse json feed");
		}

		return root;
	}

	Json::Value scraper::download(std::string const& uri)
	{
		return stubborn::attempt<Json::Value>([&](){
			return parse(uri, dl.fetch(uri).body);
		});
	}

	bool scraper::is_blacklisted(std::string const& uri)
	{
		if(!blacklist.insert(uri).second) // Already visited uri
			return true;

		if(uri.find("%2F") != std::string::npos) // Bug in AH server, will get 404
			return true;

		if(uri.find("merk=100%") != std::string::npos) // Ditto
			return true;

		return false;
	}

	void scraper::order(page_t const& p)
	{
		if(is_blacklisted(p.uri))
			return;

		m.schedule(p.uri, [&, p](downloader::response const& response) {
			process(p, response);
		});
	}

	void scraper::process(const page_t &current_page, const downloader::response &response)
	{
		page_count++;

		/* Two modes:
		 * - register_tags, fetches all products via the "Filters", goes through them in-order.
		 * - !register_tags, fetches all products via inline ProductLanes and SeeMore widgets
		 * The first takes an order more time than the second.
		 * The first actually maps all categories and tags, which do not change often.
		 * I suggest you run a scrape with this tag at most once a week.
		 * Use sparingly.
		 */
		Json::Value cat_root(parse(current_page.uri, response.body));
		for(auto const& lane : cat_root["_embedded"]["lanes"])
		{
			if(register_tags && lane["id"].asString() == "Filters" && current_page.expand)
			{
				// Only process filters exhaustively if register_tags is enabled
				parse_filterlane(lane, current_page);
			}
			else if(lane["type"].asString() == "ProductLane")
			{
				parse_productlane(lane, current_page);
			}
			else if(!register_tags && lane["type"].asString() == "SeeMoreLane")
			{
				parse_seemorelane(lane, current_page);
			}
		}
	}

	void scraper::add_tag_to_hierarchy_f(std::vector<message::tag> const& _parent_tags, message::tag const& current_tag)
	{
		if(current_tag.category != "Soort")
			return; // Other categories do not possess an hierarchy.

		std::vector<message::tag> parent_tags(_parent_tags.size());
		std::reverse_copy(std::begin(_parent_tags), std::end(_parent_tags), std::begin(parent_tags));
		auto parent_it = std::find_if(std::begin(parent_tags), std::end(parent_tags), [&](message::tag const& t){
			return t.category == current_tag.category;
		});

		if(parent_it == std::end(parent_tags))
			return; // Do not add

		message::tag const& parent_tag = *parent_it;

		auto hierarchy_it(tag_hierarchy.find(parent_tag));
		if(hierarchy_it == std::end(tag_hierarchy))
			tag_hierarchy.emplace(parent_tag, std::set<message::tag>({ current_tag }));
		else
		{
			if(!hierarchy_it->second.emplace(current_tag).second)
				return;
		}

		// Emit hierarchy finding
		tag_hierarchy_callback(parent_tag, current_tag);
	}

	void scraper::parse_filterlane(Json::Value const& lane, page_t const& current_page)
	{
		for(auto const& filter_bar : lane["_embedded"]["items"])
		{
			if(filter_bar["resourceType"].asString() != "FilterBar")
				std::runtime_error("Unexpected element under Filters");

			for(auto const& filter : filter_bar["_embedded"]["filters"])
			{
				std::string filter_label = filter["label"].asString();
				for(auto const& cat : filter["_embedded"]["filterItems"])
				{
					std::string uri = cat["navItem"]["link"]["href"].asString();
					std::string title = cat["label"].asString();
					remove_hyphens(title);

					message::tag tag({title, filter_label});
					add_tag_to_hierarchy_f(current_page.tags, tag);

					std::vector<message::tag> tags;
					tags.insert(tags.end(), current_page.tags.begin(), current_page.tags.end());
					tags.push_back(tag);

					order({rest_uri + uri, title, true, tags});
				}

				break; // Only process first in bar, until none are left. (will fetch everything eventually)
			}
		}
	}

	void scraper::parse_productlane(Json::Value const& lane, page_t const& current_page)
	{
		std::string lane_name = lane["id"].asString();

		std::vector<message::tag> tags;
		tags.insert(tags.end(), current_page.tags.begin(), current_page.tags.end());
		tags.push_back({lane_name, std::string("Soort")});

		for(auto const& lane_item : lane["_embedded"]["items"])
		{
			std::string lane_type = lane_item["type"].asString();
			if(lane_type == "Product")
			{
				auto const& product = lane_item["_embedded"]["product"];
				interpreter::interpret(product, current_page, product_callback);
				product_count++;
			}
			else if(!register_tags && lane_type == "SeeMore")
			{
				if(lane_item["navItem"]["link"]["pageType"] == "legacy") // Old-style page in SeeMore Editorial
					continue;

				order({rest_uri + lane_item["navItem"]["link"]["href"].asString(), lane_name, true, tags});
			}
		}
	}

	void scraper::parse_seemorelane(Json::Value const& lane, page_t const& current_page)
	{
		for(auto const& lane_item : lane["_embedded"]["items"])
		{
			std::string title = lane_item["text"]["title"].asString();
			remove_hyphens(title);
			std::string uri = lane_item["navItem"]["link"]["href"].asString();

			std::vector<message::tag> tags;
			tags.insert(tags.end(), current_page.tags.begin(), current_page.tags.end());
			tags.push_back({title, std::string("Soort")});

			order({rest_uri + uri, title, true, tags});
		}
	}

	void scraper::scrape()
	{
		product_count = 0;
		page_count = 0;
		error_count = 0;

		Json::Value producten_root(download(rest_uri + "/producten"));

		for(auto const& lane : producten_root["_embedded"]["lanes"])
		{
			if(lane["id"].asString() != "productCategoryNavigation")
				continue;

			for(auto const& cat : lane["_embedded"]["items"])
			{
				std::string title = cat["title"].asString();
				std::string uri = cat["navItem"]["link"]["href"].asString();

				remove_hyphens(title);

				order({rest_uri + uri, title, true, {message::tag{title, std::string("Soort")}}});
			}
		}

		m.process_all();
		std::cerr << "Pages: " << page_count << ", products: " << product_count << ", errors: " << error_count << std::endl;
	}

	raw scraper::download_image(const std::string& uri)
	{
		std::string buf(dl.fetch(uri).body);
		return raw(buf.data(), buf.length());
	}
}
<|endoftext|>


<commit_before>/*
 *   Copyright 2009 by Chani Armitage <chani@kde.org>
 *   Copyright 2013 by Thorsten Staerk <kde@staerk.de>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, 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 General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "launch.h"

#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneWheelEvent>
#include <QFileInfo>

#include <KDebug>
#include <KIcon>
#include <KMenu>

#include <Plasma/DataEngine>
#include <Plasma/Containment>
#include <Plasma/Service>

ConTextMenu::ConTextMenu(QObject *parent, const QVariantList &args)
    : Plasma::ContainmentActions(parent, args)
    , m_action(new QAction(this))
{
    m_menu = new KMenu();
    connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(switchTo(QAction*)));
    m_action->setMenu(m_menu);
}

ConTextMenu::~ConTextMenu()
{
    delete m_menu;
}

void ConTextMenu::init(const KConfigGroup &)
{
}

void ConTextMenu::contextEvent(QEvent *event)
{
    makeMenu();
    m_menu->adjustSize();
    m_menu->exec(popupPosition(m_menu->size(), event));
}

void ConTextMenu::makeMenu()
{
    addApps(m_menu);
}

QList<QAction *> ConTextMenu::contextualActions()
{
    m_menu->clear(); // otherwise every time you build it it will duplicate its content
    makeMenu();
    QList<QAction *> list;
    list << m_action;
    return list;
}

bool ConTextMenu::addApps(QMenu *menu)
{
    menu->clear();

    QAction* action = menu->addAction(KIcon("system-run"), "Open a console");
    action->setData("kde4-konsole.desktop");

    action = menu->addAction(KIcon("firefox"), "Surf the web");
    action->setData("firefox.desktop");

    action = menu->addAction(KIcon("ksnapshot"), "Take a screenshot");
    action->setData("kde4-ksnapshot.desktop");

    QAction* sep1 = new QAction(this);
    sep1->setSeparator(true);
    menu->addAction(sep1);

    Plasma::Containment *c = containment();
    Q_ASSERT(c);
    menu->addAction(c->action("configure"));

    return true;
}

void ConTextMenu::switchTo(QAction *action)
{
    QString source = action->data().toString();
    kDebug() << source;
    Plasma::Service *service = dataEngine("apps")->serviceForSource(source);
    if (service)
    {
        service->startOperationCall(service->operationDescription("launch"));
    }
}

#include "launch.moc"
<commit_msg>starting with the KConfig frameWork<commit_after>/*
 *   Copyright 2009 by Chani Armitage <chani@kde.org>
 *   Copyright 2013 by Thorsten Staerk <kde@staerk.de>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, 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 General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "launch.h"

#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneWheelEvent>
#include <QFileInfo>

#include <KDebug>
#include <KIcon>
#include <KMenu>
#include <KSharedConfig>

#include <Plasma/DataEngine>
#include <Plasma/Containment>
#include <Plasma/Service>

ConTextMenu::ConTextMenu(QObject *parent, const QVariantList &args)
    : Plasma::ContainmentActions(parent, args)
    , m_action(new QAction(this))
{
    KSharedConfigPtr config = KGlobal::config();

    // This only works with Linux but it will print the name of the actual config file
    QString qs("echo '");
    qs.append(config->name());
    qs.append("' >>/tmp/test");
    qs.toAscii().constData();
    system(qs.toAscii().constData());

    m_menu = new KMenu();
    connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(switchTo(QAction*)));
    m_action->setMenu(m_menu);
}

ConTextMenu::~ConTextMenu()
{
    delete m_menu;
}

void ConTextMenu::init(const KConfigGroup &)
{
}

void ConTextMenu::contextEvent(QEvent *event)
{
    makeMenu();
    m_menu->adjustSize();
    m_menu->exec(popupPosition(m_menu->size(), event));
}

void ConTextMenu::makeMenu()
{
    addApps(m_menu);
}

QList<QAction *> ConTextMenu::contextualActions()
{
    m_menu->clear(); // otherwise every time you build it it will duplicate its content
    makeMenu();
    QList<QAction *> list;
    list << m_action;
    return list;
}

bool ConTextMenu::addApps(QMenu *menu)
{
    menu->clear();

    QAction* action = menu->addAction(KIcon("system-run"), "Open a console");
    action->setData("kde4-konsole.desktop");

    action = menu->addAction(KIcon("firefox"), "Surf the web");
    action->setData("firefox.desktop");

    action = menu->addAction(KIcon("ksnapshot"), "Take a screenshot");
    action->setData("kde4-ksnapshot.desktop");

    QAction* sep1 = new QAction(this);
    sep1->setSeparator(true);
    menu->addAction(sep1);

    Plasma::Containment *c = containment();
    Q_ASSERT(c);
    menu->addAction(c->action("configure"));

    return true;
}

void ConTextMenu::switchTo(QAction *action)
{
    QString source = action->data().toString();
    kDebug() << source;
    Plasma::Service *service = dataEngine("apps")->serviceForSource(source);
    if (service)
    {
        service->startOperationCall(service->operationDescription("launch"));
    }
}

#include "launch.moc"
<|endoftext|>


<commit_before>
// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include "tool3.h"
#include <Richedit.h>
#include "MainFrm.h"
#include <map>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
extern VOID c(VOID *);

// CMainFrame

IMPLEMENT_DYNAMIC(CMainFrame, CWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CWnd)
	ON_WM_CREATE()
	ON_BN_CLICKED(2133,tr)
	ON_BN_CLICKED(233,w)
	ON_BN_CLICKED(2233,uw)
	ON_BN_CLICKED(22,ef)
	ON_WM_DESTROY()
	ON_REGISTERED_MESSAGE(WM_ret, &CMainFrame::OnRet)   //that's a piece of class wizard production after "Add cutom message" with "registered message".
	// WM_ret stays undefined that moment so .
	ON_WM_CLOSE()
	ON_MESSAGE(WM_CTLCOLORSTATIC, &CMainFrame::OnCtlcolorstatic)
END_MESSAGE_MAP()

// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
	// TODO: add member initialization code here
}

CMainFrame::~CMainFrame()
{
}

// CMainFrame message handlers

class r:public CFolderPickerDialog
{
public:
	CString f;
	int last;
	void init() { f = m_szFileName; }
};
r *t;
HWND hc,hz;
CProgressCtrl *dc;
CProgressCtrl *t7;
CButton *bh;
CButton *q;
CButton *finA;
CButton *cmdos;
CStatic *b7;
ITaskbarList3 *bhr;
HANDLE cl;

DWORD CALLBACK E(DWORD_PTR dw, LPBYTE pb, LONG cb, LONG *pcb)
{
    std::wstringstream *fr = (std::wstringstream *)dw;
    fr->write((wchar_t *)pb, int(cb/2));
    *pcb = cb;
    return 0;
}

std::map< state , std::wstring> braze;

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{

	t7=	new CProgressCtrl();
	dc= new CProgressCtrl();
	cl=CreateEvent(NULL,1,0,NULL);
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	bh=new CButton();

	b7=new CStatic();
	q=new CButton();
	finA=new CButton();
	cmdos=new CButton();
	CBitmap wq[2];

	wq[0].LoadBitmap(IDB_BITMAP1);
	wq[1].LoadBitmap(IDB_BITMAP4);

	wchar_t w[740];
				ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.",w,740);
				FILE *xf;
				_wfopen_s(&xf,w,L"r+");
				DWORD c = 0;
			if(xf)
			{
					fwscanf(xf,L"%[^\n]%*c",remmi);          //stuff from msdn. works with and w/o \n
					t=new r();
					t->f = remmi;
					if(!(feof(xf)))
					{
						ZeroMemory(remmi,1218*2);
						fwscanf(xf,L"%[^\n]%*c",remmi);
					}
					else
					{
						wcscpy_s(remmi,L"--block-sync-size 20 --db-sync-mode fastest:async:8750 --prep-blocks-threads 4");
						fwprintf(xf,L"\n%s",remmi);      // r+ shifts write pos when read.
					}
					fclose(xf);
			}
			else
			{
					c=WS_DISABLED;
					wcscpy_s(remmi,L"--block-sync-size 20 --db-sync-mode fastest:async:8750 --prep-blocks-threads 4");
					t=NULL;
			}

	braze.insert(std::map< state , std::wstring>::value_type( q_quit, L"quit"));
	braze.insert(std::map< state , std::wstring>::value_type( q_gundrop, L"gundrop"));
	braze.insert(std::map< state , std::wstring>::value_type( q_stay, L"stay"));
	braze.insert(std::map< state , std::wstring>::value_type( q_stop, L"q_stop"));
	braze.insert(std::map< state , std::wstring>::value_type( q_torque, L"torque"));

	bh->Create(L"start",BS_BITMAP|WS_CHILD|WS_VISIBLE|c,CRect(50,50,170,100),this,2133);
	bh->SetBitmap(wq[0]);
	q->Create(L"stop",BS_BITMAP|WS_CHILD|WS_VISIBLE|WS_DISABLED,CRect(50+170,50,170+170,100),this,233);
	q->SetBitmap(wq[1]);
	finA->Create(L"locate",BS_TEXT|WS_CHILD|WS_VISIBLE,CRect(0+270,20+292,59+270,48+292),this,2233);
	cmdos->Create(L"commandos",BS_TEXT|WS_CHILD|WS_VISIBLE|WS_DISABLED,CRect(0+337,20+292,97+341,48+292),this,22);

	dc->Create(WS_VISIBLE|WS_CHILD|PBS_SMOOTH,CRect(120,100+130,120+220,100+170),this,21);
	t7->Create(WS_VISIBLE|WS_CHILD|PBS_VERTICAL|PBS_SMOOTHREVERSE|PBS_SMOOTH,CRect(10,200,10+19,200+140),this,129);
	t7->SetRange(0,140);
	b7->Create(L"to go :",WS_CHILD|WS_VISIBLE|SS_WHITEFRAME|SS_SIMPLE,CRect(40,290,373,320),this);
	 hc=CreateWindowEx(WS_EX_NOPARENTNOTIFY, MSFTEDIT_CLASS,remmi,
		ES_MULTILINE|ES_AUTOVSCROLL| WS_VISIBLE | WS_CHILD |WS_TABSTOP|WS_VSCROLL,
        1, 350, 450, 201,
		this->m_hWnd, NULL, h, NULL);
	HFONT newFont = CreateFont(22, 0, 0, 0,0 , FALSE, FALSE, FALSE, DEFAULT_CHARSET,
    OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
    DEFAULT_PITCH | FF_DECORATIVE, L"Lucida Console");

	::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
	hz=this->m_hWnd;
	::PostMessage(b7->m_hWnd,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
	return 0;
}
	HANDLE stdinRd, stdinWr, stdoutRd, stdoutWr;
state bren = q_stay;
int cr,f,terminator;
PROCESS_INFORMATION pi;

int terminator2;

void CMainFrame::tr() //  bh->Create(L"start",BS_BITMAP|WS_CHILD|WS_VISIBLE|c,CRect(50,50,170,100),this,2133);
{
	std::wstringstream fr;

	EDITSTREAM es = {};
	if(trigger)
	{
		es.dwCookie = (DWORD_PTR) &fr;
		es.pfnCallback = E;
		::SendMessage(hc, EM_STREAMOUT, SF_TEXT|SF_UNICODE, (LPARAM)&es);
		if(!iswspace(*fr.str().cbegin())) fr.str(L' ' + fr.str());
		ZeroMemory(remmi,1218*2);
		fr.read(remmi,747);
		trigger=0;
	}

	SECURITY_ATTRIBUTES sa={sizeof(SECURITY_ATTRIBUTES), NULL, true};
			CreatePipe(&stdinRd, &stdinWr, &sa, 10000);
            CreatePipe(&stdoutRd,&stdoutWr, &sa,500000);
			if(pi.hProcess) CloseHandle(pi.hProcess);
			STARTUPINFO si = {};

			si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
            si.wShowWindow = SW_HIDE;
            si.hStdOutput = stdoutWr;
            si.hStdError = stdoutWr;
            si.hStdInput = stdinRd;
			int h=CreateProcess(t->f + L"\\monerod.exe",remmi, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, t->f, &si, &pi);
			if(!h)
			{

				MessageBox(L"Bad start,check location");
				return;
			}
			bren=q_torque;
			rew=AfxBeginThread((AFX_THREADPROC)c,NULL);
}

void CMainFrame::w()			   // q->Create(L"stop",BS_BITMAP|WS_CHILD|WS_VISIBLE|WS_DISABLED,CRect(50+170,50,170+170,100),this,233);
{
	bren = bren == q_quit ? bren : q_stop;
	char k[100];
	strcpy(k,"exit\n");
    DWORD numberofbyteswritten;
	WriteFile(stdinWr, k, 5, &numberofbyteswritten, NULL);
}

void CMainFrame::uw()				// finA->Create(L"locate",BS_TEXT|WS_CHILD|WS_VISIBLE,CRect(0+280,20+292,59+280,48+292),this,2233);
{
	if(!t) t=new r();
	int c= t->DoModal();

	wchar_t w[740];
	ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.",w,730);
	FILE *xf;

	if(c==IDOK)
	{
		xf=_wfopen(w,L"w+");
		t->init();
		fwprintf(xf,L"%s",t->f);
		fwprintf(xf,L"\n%s",remmi);
		fclose(xf);
		bh->EnableWindow();
	}
	else if(t->f.IsEmpty()) { delete t; t=NULL; }
}

HBRUSH hbrBkgnd;
void CMainFrame::OnDestroy()
{
	CWnd::OnDestroy();
	if(t) delete t;
	delete bh;
	delete q;
	delete dc;
	delete finA;
	delete cmdos;
	delete t7;
	delete b7;
//	delete rew;
	DeleteObject(hbrBkgnd);
}

VOID hammer(VOID *)
{
	CoInitializeEx(NULL,COINIT_MULTITHREADED); //used only by extra thread for now
	CoCreateInstance(CLSID_TaskbarList,NULL,CLSCTX_INPROC_SERVER,IID_ITaskbarList3,(LPVOID*)&bhr); //no inter-process here.pointer grabs smth finally
	bhr->HrInit();								//not sure
	WaitForSingleObject(cl,INFINITE);
	bhr->Release();
	bhr=NULL;					//  recommendation about to deal with COM
	CoUninitialize();
}

afx_msg LRESULT CMainFrame::OnRet(WPARAM wParam, LPARAM lParam) //Win7 progress bar over a taskbar's bay of this app. WM_ret finished up here.
{
	rewh = AfxBeginThread((AFX_THREADPROC)hammer,NULL);
	return 0;
}

void CMainFrame::OnClose()
{
		FILE *xf;
		wchar_t w[840],ferrum[324];
DWORD c;
		switch (bren)
		{
		case q_quit:
			c = WaitForSingleObject(pi.hProcess, 0);
			if (c != WAIT_TIMEOUT)
			{
				SetEvent(cl);
				if (t)
				{
					ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.", w, 930);
					xf = _wfopen(w, L"w+");
					fwprintf(xf, L"%s", t->f);
					if (remmi[0] == L' ')fwprintf(xf, L"\n%s", &remmi[1]);
					else fwprintf(xf, L"\n%s", remmi);
					fclose(xf);
				}
				WaitForSingleObject(rewh->m_hThread, INFINITE);
				CWnd::OnClose();
			}
			break;
		case q_stay:
			SetEvent(cl);
			if (t)
			{
				ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.", w, 1310);
				xf = _wfopen(w, L"w+");
				fwprintf(xf, L"%s", t->f);
				if (remmi[0] == L' ')	fwprintf(xf, L"\n%s", &remmi[1]);
				else fwprintf(xf, L"\n%s", remmi);
				fclose(xf);
			}
			WaitForSingleObject(rewh->m_hThread, INFINITE);
			CWnd::OnClose();
			break;
	default:
			if (*braze[bren].crbegin() != L'q') {	bren = q_quit; this->w(); }
			bren = q_quit;
			break;
		}

}

void CMainFrame::ef()
{
	SETTEXTEX fw;
		fw.flags=4;
	fw.codepage=1200;
	::SendMessage(hc,EM_SETTEXTEX,(WPARAM)&fw,(LPARAM)remmi);
	trigger = bren == q_stay;
}

afx_msg LRESULT CMainFrame::OnCtlcolorstatic(WPARAM wParam, LPARAM lParam)
{
	HDC hdcStatic = (HDC)wParam;
	SetTextColor(hdcStatic, RGB(2, 5, 55));
	SetBkColor(hdcStatic, RGB(255, 255, 255));
    if (hbrBkgnd == NULL) hbrBkgnd = CreateSolidBrush(RGB(255, 255, 255));
    return (INT_PTR)hbrBkgnd;
}
<commit_msg>no message<commit_after>
// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include "tool3.h"
#include <Richedit.h>
#include "MainFrm.h"
#include <map>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
extern VOID c(VOID *);

// CMainFrame

IMPLEMENT_DYNAMIC(CMainFrame, CWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CWnd)
	ON_WM_CREATE()
	ON_BN_CLICKED(2133,tr)
	ON_BN_CLICKED(233,w)
	ON_BN_CLICKED(2233,uw)
	ON_BN_CLICKED(22,ef)
	ON_WM_DESTROY()
	ON_REGISTERED_MESSAGE(WM_ret, &CMainFrame::OnRet)   //that's a piece of class wizard production after "Add cutom message" with "registered message".
	// WM_ret stays undefined that moment so .
	ON_WM_CLOSE()
	ON_MESSAGE(WM_CTLCOLORSTATIC, &CMainFrame::OnCtlcolorstatic)
END_MESSAGE_MAP()

// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
	// TODO: add member initialization code here
}

CMainFrame::~CMainFrame()
{
}

// CMainFrame message handlers

class r:public CFolderPickerDialog
{
public:
	CString f;
	int last;
	void init() { f = m_szFileName; }
};
r *t;
HWND hc,hz;
CProgressCtrl *dc;
CProgressCtrl *t7;
CButton *bh;
CButton *q;
CButton *finA;
CButton *cmdos;
CStatic *b7;
ITaskbarList3 *bhr;
HANDLE cl;

DWORD CALLBACK E(DWORD_PTR dw, LPBYTE pb, LONG cb, LONG *pcb)
{
    std::wstringstream *fr = (std::wstringstream *)dw;
    fr->write((wchar_t *)pb, int(cb/2));
    *pcb = cb;
    return 0;
}

std::map< state , std::wstring> braze;

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{

	t7=	new CProgressCtrl();
	dc= new CProgressCtrl();
	cl=CreateEvent(NULL,1,0,NULL);
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	bh=new CButton();

	b7=new CStatic();
	q=new CButton();
	finA=new CButton();
	cmdos=new CButton();
	CBitmap wq[2];

	wq[0].LoadBitmap(IDB_BITMAP1);
	wq[1].LoadBitmap(IDB_BITMAP4);

	wchar_t w[740];
				ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.",w,740);
				FILE *xf;
				_wfopen_s(&xf,w,L"r+");
				DWORD c = 0;
			if(xf)
			{
					fwscanf(xf,L"%[^\n]%*c",remmi);          //stuff from msdn. works with and w/o \n
					t=new r();
					t->f = remmi;
					if(!(feof(xf)))
					{
						ZeroMemory(remmi,1218*2);
						fwscanf(xf,L"%[^\n]%*c",remmi);
					}
					else
					{
						wcscpy_s(remmi,L"--block-sync-size 20 --db-sync-mode fastest:async:8750 --prep-blocks-threads 4");
						fwprintf(xf,L"\n%s",remmi);      // r+ shifts write pos when read.
					}
					fclose(xf);
			}
			else
			{
					c=WS_DISABLED;
					wcscpy_s(remmi,L"--block-sync-size 20 --db-sync-mode fastest:async:8750 --prep-blocks-threads 4");
					t=NULL;
			}

	braze[q_quit]= L"quit";
	braze[q_gundrop]= L"gundrop";
	braze[q_stay] = L"stay";
	braze[q_stop]= L"q_stop";
	braze[q_torque] = L"torque";

	bh->Create(L"start",BS_BITMAP|WS_CHILD|WS_VISIBLE|c,CRect(50,50,170,100),this,2133);
	bh->SetBitmap(wq[0]);
	q->Create(L"stop",BS_BITMAP|WS_CHILD|WS_VISIBLE|WS_DISABLED,CRect(50+170,50,170+170,100),this,233);
	q->SetBitmap(wq[1]);
	finA->Create(L"locate",BS_TEXT|WS_CHILD|WS_VISIBLE,CRect(0+270,20+292,59+270,48+292),this,2233);
	cmdos->Create(L"commandos",BS_TEXT|WS_CHILD|WS_VISIBLE|WS_DISABLED,CRect(0+337,20+292,97+341,48+292),this,22);

	dc->Create(WS_VISIBLE|WS_CHILD|PBS_SMOOTH,CRect(120,100+130,120+220,100+170),this,21);
	t7->Create(WS_VISIBLE|WS_CHILD|PBS_VERTICAL|PBS_SMOOTHREVERSE|PBS_SMOOTH,CRect(10,200,10+19,200+140),this,129);
	t7->SetRange(0,140);
	b7->Create(L"to go :",WS_CHILD|WS_VISIBLE|SS_WHITEFRAME|SS_SIMPLE,CRect(40,290,373,320),this);
	 hc=CreateWindowEx(WS_EX_NOPARENTNOTIFY, MSFTEDIT_CLASS,remmi,
		ES_MULTILINE|ES_AUTOVSCROLL| WS_VISIBLE | WS_CHILD |WS_TABSTOP|WS_VSCROLL,
        1, 350, 450, 201,
		this->m_hWnd, NULL, h, NULL);
	HFONT newFont = CreateFont(22, 0, 0, 0,0 , FALSE, FALSE, FALSE, DEFAULT_CHARSET,
    OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
    DEFAULT_PITCH | FF_DECORATIVE, L"Lucida Console");

	::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
	hz=this->m_hWnd;
	::PostMessage(b7->m_hWnd,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
	return 0;
}
	HANDLE stdinRd, stdinWr, stdoutRd, stdoutWr;
state bren = q_stay;
int cr,f,terminator;
PROCESS_INFORMATION pi;

int terminator2;

void CMainFrame::tr() //  bh->Create(L"start",BS_BITMAP|WS_CHILD|WS_VISIBLE|c,CRect(50,50,170,100),this,2133);
{
	std::wstringstream fr;

	EDITSTREAM es = {};
	if(trigger)
	{
		es.dwCookie = (DWORD_PTR) &fr;
		es.pfnCallback = E;
		::SendMessage(hc, EM_STREAMOUT, SF_TEXT|SF_UNICODE, (LPARAM)&es);
		if(!iswspace(*fr.str().cbegin())) fr.str(L' ' + fr.str());
		ZeroMemory(remmi,1218*2);
		fr.read(remmi,747);
		trigger=0;
	}

	SECURITY_ATTRIBUTES sa={sizeof(SECURITY_ATTRIBUTES), NULL, true};
			CreatePipe(&stdinRd, &stdinWr, &sa, 10000);
            CreatePipe(&stdoutRd,&stdoutWr, &sa,500000);
			if(pi.hProcess) CloseHandle(pi.hProcess);
			STARTUPINFO si = {};

			si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
            si.wShowWindow = SW_HIDE;
            si.hStdOutput = stdoutWr;
            si.hStdError = stdoutWr;
            si.hStdInput = stdinRd;
			int h=CreateProcess(t->f + L"\\monerod.exe",remmi, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, t->f, &si, &pi);
			if(!h)
			{

				MessageBox(L"Bad start,check location");
				return;
			}
			bren=q_torque;
			rew=AfxBeginThread((AFX_THREADPROC)c,NULL);
}

void CMainFrame::w()			   // q->Create(L"stop",BS_BITMAP|WS_CHILD|WS_VISIBLE|WS_DISABLED,CRect(50+170,50,170+170,100),this,233);
{
	bren = bren == q_quit ? bren : q_stop;
	char k[100];
	strcpy(k,"exit\n");
    DWORD numberofbyteswritten;
	WriteFile(stdinWr, k, 5, &numberofbyteswritten, NULL);
}

void CMainFrame::uw()				// finA->Create(L"locate",BS_TEXT|WS_CHILD|WS_VISIBLE,CRect(0+280,20+292,59+280,48+292),this,2233);
{
	if(!t) t=new r();
	int c= t->DoModal();

	wchar_t w[740];
	ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.",w,730);
	FILE *xf;

	if(c==IDOK)
	{
		xf=_wfopen(w,L"w+");
		t->init();
		fwprintf(xf,L"%s",t->f);
		fwprintf(xf,L"\n%s",remmi);
		fclose(xf);
		bh->EnableWindow();
	}
	else if(t->f.IsEmpty()) { delete t; t=NULL; }
}

HBRUSH hbrBkgnd;
void CMainFrame::OnDestroy()
{
	CWnd::OnDestroy();
	if(t) delete t;
	delete bh;
	delete q;
	delete dc;
	delete finA;
	delete cmdos;
	delete t7;
	delete b7;
//	delete rew;
	DeleteObject(hbrBkgnd);
}

VOID hammer(VOID *)
{
	CoInitializeEx(NULL,COINIT_MULTITHREADED); //used only by extra thread for now
	CoCreateInstance(CLSID_TaskbarList,NULL,CLSCTX_INPROC_SERVER,IID_ITaskbarList3,(LPVOID*)&bhr); //no inter-process here.pointer grabs smth finally
	bhr->HrInit();								//not sure
	WaitForSingleObject(cl,INFINITE);
	bhr->Release();
	bhr=NULL;					//  recommendation about to deal with COM
	CoUninitialize();
}

afx_msg LRESULT CMainFrame::OnRet(WPARAM wParam, LPARAM lParam) //Win7 progress bar over a taskbar's bay of this app. WM_ret finished up here.
{
	rewh = AfxBeginThread((AFX_THREADPROC)hammer,NULL);
	return 0;
}

void CMainFrame::OnClose()
{
		FILE *xf;
		wchar_t w[840],ferrum[324];
DWORD c;
		switch (bren)
		{
		case q_quit:
			c = WaitForSingleObject(pi.hProcess, 0);
			if (c != WAIT_TIMEOUT)
			{
				SetEvent(cl);
				if (t)
				{
					ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.", w, 930);
					xf = _wfopen(w, L"w+");
					fwprintf(xf, L"%s", t->f);
					if (remmi[0] == L' ')fwprintf(xf, L"\n%s", &remmi[1]);
					else fwprintf(xf, L"\n%s", remmi);
					fclose(xf);
				}
				WaitForSingleObject(rewh->m_hThread, INFINITE);
				CWnd::OnClose();
			}
			break;
		case q_stay:
			SetEvent(cl);
			if (t)
			{
				ExpandEnvironmentStrings(L"%USERPROFILE%\\Documents\\fold.", w, 1310);
				xf = _wfopen(w, L"w+");
				fwprintf(xf, L"%s", t->f);
				if (remmi[0] == L' ')	fwprintf(xf, L"\n%s", &remmi[1]);
				else fwprintf(xf, L"\n%s", remmi);
				fclose(xf);
			}
			WaitForSingleObject(rewh->m_hThread, INFINITE);
			CWnd::OnClose();
			break;
	default:
			if (*braze[bren].crbegin() != L'q') {	bren = q_quit; this->w(); }
			bren = q_quit;
			break;
		}

}

void CMainFrame::ef()
{
	SETTEXTEX fw;
		fw.flags=4;
	fw.codepage=1200;
	::SendMessage(hc,EM_SETTEXTEX,(WPARAM)&fw,(LPARAM)remmi);
	trigger = bren == q_stay;
}

afx_msg LRESULT CMainFrame::OnCtlcolorstatic(WPARAM wParam, LPARAM lParam)
{
	HDC hdcStatic = (HDC)wParam;
	SetTextColor(hdcStatic, RGB(2, 5, 55));
	SetBkColor(hdcStatic, RGB(255, 255, 255));
    if (hbrBkgnd == NULL) hbrBkgnd = CreateSolidBrush(RGB(255, 255, 255));
    return (INT_PTR)hbrBkgnd;
}
<|endoftext|>


<commit_before>//======= Genetic.cpp -  Guide to Exploration of Otimization's Set -*- C++ -*-==//
////
////              The LLVM Time Cost Analyser Infrastructure
////
////  This file is distributed under the MIT License. See LICENSE.txt for details.
////
////===----------------------------------------------------------------------===//
/////
///// \file
///// \brief This file implements a tool that, when given a llvm code and its
///// profiling information, returns the best otimization sequence from a genetic
///// algorithm.
/////
////===----------------------------------------------------------------------===//

#include "GEOS.h"

#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/IR/LLVMContext.h"

#include "GEOSCommandLineParser.h"
#include "OfflineLearning/CodeMetricBase.h"
#include "OfflineLearning/AccuracyBase.h"
#include "OfflineLearning/CorrectionBase.h"
#include "OfflineLearning/OptAccuracyBase.h"

#include <vector>
#include <limits>
#include <random>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include "papi.h"
#include <list>
#include <queue>
#include <float.h>

#include <cstdlib>
#include <ctime>

static cl::opt<std::string>
MBasePath("metrics", cl::desc("Base of metrics"),
    cl::value_desc(".txt"));
static cl::alias
MBaseAlias("m", cl::desc("Alias for -metrics"), cl::aliasopt(MBasePath));

static cl::opt<std::string>
ABasePath("accuracy", cl::desc("Base of Accuracy"),
    cl::value_desc(".txt"));
static cl::alias
ABaseAlias("a", cl::desc("Alias for -accuracy"), cl::aliasopt(ABasePath));

static cl::opt<std::string>
CBasePath("correction-folder", cl::desc("Folder with corrections"),
    cl::value_desc(".txt"));
static cl::alias
CBaseAlias("cf", cl::desc("Alias for -correction-folder"), cl::aliasopt(CBasePath));

static cl::opt<std::string>
OABasePath("opt-accuracy-folder", cl::desc("Folder with accuracy for each otimization"),
    cl::value_desc(".txt"));
static cl::alias
OABaseAlias("oaf", cl::desc("Alias for -opt-accuracy"), cl::aliasopt(OABasePath));

static cl::opt<unsigned> SIZE("pop-size", cl::desc("Size of population"));
static cl::alias SIZEAlias("s", cl::desc("Alias for -pop-size"),
    cl::aliasopt(SIZE));

static cl::opt<unsigned> BSIZE("opt-list-size", cl::desc("Max size of best sequence list"));
static cl::alias BSIZEAlias("ols", cl::desc("Alias for best-sequence size"),
    cl::aliasopt(BSIZE));

static cl::opt<unsigned> TSIZE("tournament-size", cl::desc("Max size of tournament"));
static cl::alias TSIZEAlias("ts", cl::desc("Alias for tournament size"),
    cl::aliasopt(TSIZE));

static cl::opt<unsigned> NOPT("length-solution", cl::desc("Max total time (in seconds)"));
static cl::alias NOPTAlias("len", cl::desc("Alias for time-max"),
    cl::aliasopt(NOPT));

static cl::opt<unsigned> TIME_MAX("time-max", cl::desc("Max total time (in seconds)"));
static cl::alias TIME_MAXAlias("tm", cl::desc("Alias for time-max"),
    cl::aliasopt(TIME_MAX));

static cl::opt<unsigned> CYCLE_MAX("cycle-max", cl::desc("Max number of cycles"));
static cl::alias CYCLE_MAXAlias("cm", cl::desc("Alias for cycle-max"),
    cl::aliasopt(CYCLE_MAX));

static cl::opt<double> MutationRate("mut-rate", cl::desc("Max total time (in seconds)"));
static cl::alias MutationRateAlias("pm", cl::desc("Alias for time-max"),
    cl::aliasopt(MutationRate));

static cl::opt<double> CrossoverRate("cross-rate", cl::desc("Max total time (in seconds)"));
static cl::alias CrossoverRateAlias("pc", cl::desc("Alias for time-max"),
    cl::aliasopt(CrossoverRate));

static cl::opt<int> Randomness("randomness", cl::desc("RandomCost"));
static cl::alias RandomnessAlias("rc", cl::desc("Alias for randomness"),
    cl::aliasopt(Randomness));

#define SIZE_STD 100
#define NOPT_STD 70
#define BSIZE_STD 5
#define TSIZE_STD 5
#define TIME_MAX_STD 300
#define CYCLE_MAX_STD 50

#define CRATE_STD 0.8
#define MRATE_STD 0.01

double getRandomDouble() {
  return rand()/RAND_MAX;
}

// ------------------------------- Types
typedef struct Solution {
  PassSequence Sequence;
  double Cost;
  bool isCalculated;

  Solution() {}
  Solution(PassSequence P, double C = DBL_MAX, bool isC = false) {
    Sequence = P;
    Cost = C;
    isCalculated = isC;
  }

  void setCost(double C) { Cost = C; isCalculated = true; }

  Solution &operator=(Solution rhs) {
    Sequence = rhs.Sequence;
    Cost = rhs.Cost;
    isCalculated = rhs.isCalculated;
    return *this;
  }
} Solution;

class CompareSolution {
  double Accuracy;
  bool getJudgement() const {
    return (Accuracy >= getRandomDouble());
  }

  public:
    CompareSolution(const double A = 1.0) {
      Accuracy = (A + 1.0)/2;
    }

    bool operator()(Solution S1, Solution S2) const {
      return ((S1.Cost > S2.Cost) == getJudgement());
    }
};

typedef std::vector<Solution> PopT;
typedef std::priority_queue<Solution, PopT, CompareSolution> BestSeqT;

// ---------------------- Functions
void initializePopulation(PopT &Population) {
  for (unsigned i = 0; i < SIZE; i++) {
    PassSequence Sequence;
    Sequence.randomize(NOPT);
    Population.push_back(Solution(Sequence));
  }
}

bool evaluate(Solution &S,
    CorrectionBaseT CorrectionBase, OptAccuracyBaseT OptAccuracyBase,
    std::shared_ptr<ProfileModule> PModule, CostEstimatorOptions Opts) {
  if (S.isCalculated) return true;

  auto NewCost = (rand() % 10) + 1;
  if (!Randomness) {
    auto PO = GEOS::applyPasses(PModule, S.Sequence);
    if (!PO) return false;
    NewCost = GEOS::analyseCost(PO, Opts);
  }

  if (MBasePath.empty()) {
    auto OptAccuracy = getPassSequenceAccuracy
      (S.Sequence, Opts, OptAccuracyBase);
    NewCost /= getCorrectionFor(S.Sequence, Opts, CorrectionBase);
    NewCost *= OptAccuracy;
  }

  S.setCost(NewCost);
  return true;
}

void evaluatePopulation(PopT &Population,
    CorrectionBaseT CorrectionBase, OptAccuracyBaseT OptAccuracyBase,
    BestSeqT &BestSequences, std::shared_ptr<ProfileModule> PModule,
    CostEstimatorOptions Opts, double EstimatedAccuracy) {

  BestSeqT OrderedPop((CompareSolution(EstimatedAccuracy)));
  BestSequences = BestSeqT(CompareSolution(EstimatedAccuracy));

  for (auto &I : Population) {
    evaluate(I, CorrectionBase, OptAccuracyBase, PModule, Opts);
    OrderedPop.push(I);
  }

  for (unsigned i = 0; i < BSIZE; i++) {
    BestSequences.push(OrderedPop.top());
    OrderedPop.pop();
  }
}

PopT selection(PopT Population, double EstimatedAccuracy) {
  unsigned MSize = Population.size()/2, PSize = Population.size();
  PopT MatingPool;
  while (MatingPool.size() < MSize) {
    BestSeqT Tournament((CompareSolution(EstimatedAccuracy)));
    for (unsigned i = 0; i < TSIZE; i++) {
      int Gene = rand() % PSize;
      Tournament.push(Population[Gene]);
    }
    MatingPool.push_back(Tournament.top());
  }
  return MatingPool;
}

PopT crossover(PopT MatingPool) {
  PopT NewPopulation;
  int MSize = (int)MatingPool.size();
  while (NewPopulation.size() <= SIZE) {
    int ParentI = rand() % MSize;
    int ParentJ = rand() % MSize;
    if (CrossoverRate >= getRandomDouble()) {
      PassSequence Crossover = MatingPool[ParentI].Sequence *
        MatingPool[ParentJ].Sequence;
      NewPopulation.push_back(Solution(Crossover));
    } else {
      NewPopulation.push_back(MatingPool[ParentI]);
      NewPopulation.push_back(MatingPool[ParentJ]);
    }
  }
  return NewPopulation;
}

void mutation(PopT &Population) {
  PassSequence MutatedSeq;
  int MaxOpt = static_cast<int>(OptimizationKind::tailcallelim);
  for (auto S : Population) {
    if (S.isCalculated) continue;
    for (unsigned i = 0; i < S.Sequence.size(); i++) {
      if (MutationRate >= getRandomDouble()) {
        MutatedSeq.add(static_cast<OptimizationKind>(rand() % MaxOpt));
      } else {
        MutatedSeq.add(S.Sequence[i]);
      }
    }
    S.Sequence = MutatedSeq;
  }
}

bool isFinished(time_t Start, int Cycles) {
  time_t total = time(0) - Start;
  printf("Time:%ld\n", total);
  if (CYCLE_MAX && TIME_MAX)
    return (total >= (int)TIME_MAX || Cycles >= (int)CYCLE_MAX);
  else if (TIME_MAX)
    return (total >= (int)TIME_MAX);
  else
    return (Cycles >= (int)CYCLE_MAX);
}

int main(int argc, char** argv) {
  srand(time(0));
  GEOS::init();

  LLVMContext &Context = getGlobalContext();
  SMDiagnostic Error;

  gcl::GEOSParseCommandLineOptions(argc, argv);
  Module *MyModule =
    parseIRFile(LLVMFilename.c_str(), Error, Context).release();

  if (!SIZE) SIZE = SIZE_STD;
  if (!BSIZE) BSIZE = BSIZE_STD;
  if (!TSIZE) TSIZE = TSIZE_STD;
  if (!NOPT) NOPT = NOPT_STD;
  if (!TIME_MAX && !CYCLE_MAX) TIME_MAX = TIME_MAX_STD;
  if (!MutationRate) MutationRate = MRATE_STD;
  if (!CrossoverRate) CrossoverRate = CRATE_STD;

  std::shared_ptr<ProfileModule> PModule(new ProfileModule(MyModule));
  CostEstimatorOptions Opts = gcl::populatePModule(PModule);

  double EstimatedAccuracy = 1;
  OptAccuracyBaseT OptAccuracyBase;
  CorrectionBaseT CorrectionBase;
  if (!MBasePath.empty() && !ABasePath.empty() && !CBasePath.empty() && !OABasePath.empty()) {
    auto MetricBase = loadMetricsBase(MBasePath);
    auto AccuracyBase = loadAccuracyBase(ABasePath);
    auto NearestMetricName = getNearestMetric(PModule, MetricBase);
    EstimatedAccuracy =
      getAccuracyFor(NearestMetricName, Opts, AccuracyBase);

    CorrectionBase =
      loadCorrectionBase(CBasePath+"/"+NearestMetricName+".estr");
    OptAccuracyBase =
      loadOptAccuracyBase(OABasePath+"/"+NearestMetricName+".ocor");
  }

  int PAPIEvents[1] = {PAPI_TOT_CYC};
  double RealInitCost =
    (GEOS::getPAPIProfile(PModule, ExecutionKind::JIT, PAPIEvents, 1))[0];

  double InitCost;
  if (Randomness)
    InitCost = (rand() % 10) + 1;
  else
    InitCost = GEOS::analyseCost(PModule, Opts);

  int Cycles = 0;
  CompareSolution CompSolVar(EstimatedAccuracy);

  BestSeqT BestSequences((CompareSolution(EstimatedAccuracy)));
  BestSeqT GlobalBest((CompareSolution(EstimatedAccuracy)));
  PopT Population;

  printf("Starting genetic...\n");

  initializePopulation(Population);
  evaluatePopulation(Population, CorrectionBase, OptAccuracyBase,
      BestSequences, PModule, Opts, EstimatedAccuracy);

  time_t Start = time(0);
  while (!isFinished(Start, Cycles)) {
    PopT MatingPool =
      selection(Population, EstimatedAccuracy);
    Population =
      crossover(MatingPool);
    mutation(Population);

    evaluatePopulation(Population, CorrectionBase, OptAccuracyBase,
        BestSequences, PModule, Opts, EstimatedAccuracy);

    BestSeqT Aux((CompareSolution(EstimatedAccuracy)));
    for (unsigned i = 0; i < BSIZE; i++) {
      Aux.push(BestSequences.top());
      BestSequences.pop();
      if (GlobalBest.size()) {
        Aux.push(GlobalBest.top());
        GlobalBest.pop();
      }
    }
    GlobalBest = BestSeqT(CompareSolution(EstimatedAccuracy));
    for (unsigned i = 0; i < BSIZE; i++) {
      GlobalBest.push(Aux.top());
      Aux.pop();
    }

    Cycles += 1;
    printf("Cycles: %d - ", Cycles);
  }

  double BestRealSpeedUp = 0;
  double BestEstSpeedUp = 0;
  Solution BestSolution;
  while (BestSequences.size() != 0) {
    auto B = BestSequences.top();
    auto PO = GEOS::applyPasses(PModule, B.Sequence);
    double RealFinalCost =
      (GEOS::getPAPIProfile(PO, ExecutionKind::JIT, PAPIEvents, 1))[0];
    double FinalCost;
    if (Randomness) FinalCost = (rand() % 10) + 1;
    else FinalCost = GEOS::analyseCost(PO, Opts);

    if ((RealInitCost/RealFinalCost) > BestRealSpeedUp) {
      BestRealSpeedUp = RealInitCost/RealFinalCost;
      BestEstSpeedUp = InitCost/FinalCost;
      BestSolution = B;
    }

    BestSequences.pop();
  }

  while (GlobalBest.size() != 0) {
    auto B = GlobalBest.top();
    auto PO = GEOS::applyPasses(PModule, B.Sequence);
    double RealFinalCost =
      (GEOS::getPAPIProfile(PO, ExecutionKind::JIT, PAPIEvents, 1))[0];
    double FinalCost;
    if (Randomness) FinalCost = (rand() % 10) + 1;
    else FinalCost = GEOS::analyseCost(PO, Opts);

    if ((RealInitCost/RealFinalCost) > BestRealSpeedUp) {
      BestRealSpeedUp = RealInitCost/RealFinalCost;
      BestEstSpeedUp = InitCost/FinalCost;
      BestSolution = B;
    }

    GlobalBest.pop();
  }

  printf("\n%f %f\n", BestEstSpeedUp,
      BestRealSpeedUp);
  return 0;
}
<commit_msg>Random in Genetic modified<commit_after>//======= Genetic.cpp -  Guide to Exploration of Otimization's Set -*- C++ -*-==//
////
////              The LLVM Time Cost Analyser Infrastructure
////
////  This file is distributed under the MIT License. See LICENSE.txt for details.
////
////===----------------------------------------------------------------------===//
/////
///// \file
///// \brief This file implements a tool that, when given a llvm code and its
///// profiling information, returns the best otimization sequence from a genetic
///// algorithm.
/////
////===----------------------------------------------------------------------===//

#include "GEOS.h"

#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/IR/LLVMContext.h"

#include "GEOSCommandLineParser.h"
#include "OfflineLearning/CodeMetricBase.h"
#include "OfflineLearning/AccuracyBase.h"
#include "OfflineLearning/CorrectionBase.h"
#include "OfflineLearning/OptAccuracyBase.h"

#include <vector>
#include <limits>
#include <random>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include "papi.h"
#include <list>
#include <queue>
#include <float.h>

#include <cstdlib>
#include <ctime>

static cl::opt<std::string>
MBasePath("metrics", cl::desc("Base of metrics"),
    cl::value_desc(".txt"));
static cl::alias
MBaseAlias("m", cl::desc("Alias for -metrics"), cl::aliasopt(MBasePath));

static cl::opt<std::string>
ABasePath("accuracy", cl::desc("Base of Accuracy"),
    cl::value_desc(".txt"));
static cl::alias
ABaseAlias("a", cl::desc("Alias for -accuracy"), cl::aliasopt(ABasePath));

static cl::opt<std::string>
CBasePath("correction-folder", cl::desc("Folder with corrections"),
    cl::value_desc(".txt"));
static cl::alias
CBaseAlias("cf", cl::desc("Alias for -correction-folder"), cl::aliasopt(CBasePath));

static cl::opt<std::string>
OABasePath("opt-accuracy-folder", cl::desc("Folder with accuracy for each otimization"),
    cl::value_desc(".txt"));
static cl::alias
OABaseAlias("oaf", cl::desc("Alias for -opt-accuracy"), cl::aliasopt(OABasePath));

static cl::opt<unsigned> SIZE("pop-size", cl::desc("Size of population"));
static cl::alias SIZEAlias("s", cl::desc("Alias for -pop-size"),
    cl::aliasopt(SIZE));

static cl::opt<unsigned> BSIZE("opt-list-size", cl::desc("Max size of best sequence list"));
static cl::alias BSIZEAlias("ols", cl::desc("Alias for best-sequence size"),
    cl::aliasopt(BSIZE));

static cl::opt<unsigned> TSIZE("tournament-size", cl::desc("Max size of tournament"));
static cl::alias TSIZEAlias("ts", cl::desc("Alias for tournament size"),
    cl::aliasopt(TSIZE));

static cl::opt<unsigned> NOPT("length-solution", cl::desc("Max total time (in seconds)"));
static cl::alias NOPTAlias("len", cl::desc("Alias for time-max"),
    cl::aliasopt(NOPT));

static cl::opt<unsigned> TIME_MAX("time-max", cl::desc("Max total time (in seconds)"));
static cl::alias TIME_MAXAlias("tm", cl::desc("Alias for time-max"),
    cl::aliasopt(TIME_MAX));

static cl::opt<unsigned> CYCLE_MAX("cycle-max", cl::desc("Max number of cycles"));
static cl::alias CYCLE_MAXAlias("cm", cl::desc("Alias for cycle-max"),
    cl::aliasopt(CYCLE_MAX));

static cl::opt<double> MutationRate("mut-rate", cl::desc("Max total time (in seconds)"));
static cl::alias MutationRateAlias("pm", cl::desc("Alias for time-max"),
    cl::aliasopt(MutationRate));

static cl::opt<double> CrossoverRate("cross-rate", cl::desc("Max total time (in seconds)"));
static cl::alias CrossoverRateAlias("pc", cl::desc("Alias for time-max"),
    cl::aliasopt(CrossoverRate));

static cl::opt<int> Randomness("randomness", cl::desc("RandomCost"));
static cl::alias RandomnessAlias("rc", cl::desc("Alias for randomness"),
    cl::aliasopt(Randomness));

#define SIZE_STD 100
#define NOPT_STD 70
#define BSIZE_STD 5
#define TSIZE_STD 5
#define TIME_MAX_STD 300
#define CYCLE_MAX_STD 50

#define CRATE_STD 0.8
#define MRATE_STD 0.01

double getRandomDouble() {
  return rand()/RAND_MAX;
}

// ------------------------------- Types
typedef struct Solution {
  PassSequence Sequence;
  double Cost;
  bool isCalculated;

  Solution() {}
  Solution(PassSequence P, double C = DBL_MAX, bool isC = false) {
    Sequence = P;
    Cost = C;
    isCalculated = isC;
  }

  void setCost(double C) { Cost = C; isCalculated = true; }

  Solution &operator=(Solution rhs) {
    Sequence = rhs.Sequence;
    Cost = rhs.Cost;
    isCalculated = rhs.isCalculated;
    return *this;
  }
} Solution;

class CompareSolution {
  double Accuracy;
  bool getJudgement() const {
    return (Accuracy >= getRandomDouble());
  }

  public:
  CompareSolution(const double A = 1.0) {
    Accuracy = (A + 1.0)/2;
  }

  bool operator()(Solution S1, Solution S2) const {
    return ((S1.Cost > S2.Cost) == getJudgement());
  }
};

typedef std::vector<Solution> PopT;
typedef std::priority_queue<Solution, PopT, CompareSolution> BestSeqT;

// ---------------------- Functions
void initializePopulation(PopT &Population) {
  for (unsigned i = 0; i < SIZE; i++) {
    PassSequence Sequence;
    Sequence.randomize(NOPT);
    Population.push_back(Solution(Sequence));
  }
}

bool evaluate(Solution &S,
    CorrectionBaseT CorrectionBase, OptAccuracyBaseT OptAccuracyBase,
    std::shared_ptr<ProfileModule> PModule, CostEstimatorOptions Opts) {
  if (S.isCalculated) return true;

  auto NewCost = (rand() % 10) + 1;
  if (!Randomness) {
    auto PO = GEOS::applyPasses(PModule, S.Sequence);
    if (!PO) return false;
    NewCost = GEOS::analyseCost(PO, Opts);
  }

  if (MBasePath.empty()) {
    auto OptAccuracy = getPassSequenceAccuracy
      (S.Sequence, Opts, OptAccuracyBase);
    NewCost /= getCorrectionFor(S.Sequence, Opts, CorrectionBase);
    NewCost *= OptAccuracy;
  }

  S.setCost(NewCost);
  return true;
}

void evaluatePopulation(PopT &Population,
    CorrectionBaseT CorrectionBase, OptAccuracyBaseT OptAccuracyBase,
    BestSeqT &BestSequences, std::shared_ptr<ProfileModule> PModule,
    CostEstimatorOptions Opts, double EstimatedAccuracy) {

  BestSeqT OrderedPop((CompareSolution(EstimatedAccuracy)));
  BestSequences = BestSeqT(CompareSolution(EstimatedAccuracy));

  for (auto &I : Population) {
    evaluate(I, CorrectionBase, OptAccuracyBase, PModule, Opts);
    OrderedPop.push(I);
  }

  for (unsigned i = 0; i < BSIZE; i++) {
    BestSequences.push(OrderedPop.top());
    OrderedPop.pop();
  }
}

PopT selection(PopT Population, double EstimatedAccuracy) {
  unsigned MSize = Population.size()/2, PSize = Population.size();
  PopT MatingPool;
  while (MatingPool.size() < MSize) {
    BestSeqT Tournament((CompareSolution(EstimatedAccuracy)));
    for (unsigned i = 0; i < TSIZE; i++) {
      int Gene = rand() % PSize;
      Tournament.push(Population[Gene]);
    }
    MatingPool.push_back(Tournament.top());
  }
  return MatingPool;
}

PopT crossover(PopT MatingPool) {
  PopT NewPopulation;
  int MSize = (int)MatingPool.size();
  while (NewPopulation.size() <= SIZE) {
    int ParentI = rand() % MSize;
    int ParentJ = rand() % MSize;
    if (CrossoverRate >= getRandomDouble()) {
      PassSequence Crossover = MatingPool[ParentI].Sequence *
        MatingPool[ParentJ].Sequence;
      NewPopulation.push_back(Solution(Crossover));
    } else {
      NewPopulation.push_back(MatingPool[ParentI]);
      NewPopulation.push_back(MatingPool[ParentJ]);
    }
  }
  return NewPopulation;
}

void mutation(PopT &Population) {
  PassSequence MutatedSeq;
  int MaxOpt = static_cast<int>(OptimizationKind::tailcallelim);
  for (auto S : Population) {
    if (S.isCalculated) continue;
    for (unsigned i = 0; i < S.Sequence.size(); i++) {
      if (MutationRate >= getRandomDouble()) {
        MutatedSeq.add(static_cast<OptimizationKind>(rand() % MaxOpt));
      } else {
        MutatedSeq.add(S.Sequence[i]);
      }
    }
    S.Sequence = MutatedSeq;
  }
}

bool isFinished(time_t Start, int Cycles) {
  time_t total = time(0) - Start;
  if (CYCLE_MAX && TIME_MAX)
    return (total >= (int)TIME_MAX || Cycles >= (int)CYCLE_MAX);
  else if (TIME_MAX)
    return (total >= (int)TIME_MAX);
  else
    return (Cycles >= (int)CYCLE_MAX);
}

int main(int argc, char** argv) {
  srand(time(0));
  GEOS::init();

  LLVMContext &Context = getGlobalContext();
  SMDiagnostic Error;

  gcl::GEOSParseCommandLineOptions(argc, argv);
  Module *MyModule =
    parseIRFile(LLVMFilename.c_str(), Error, Context).release();

  if (!SIZE) SIZE = SIZE_STD;
  if (!BSIZE) BSIZE = BSIZE_STD;
  if (!TSIZE) TSIZE = TSIZE_STD;
  if (!NOPT) NOPT = NOPT_STD;
  if (!TIME_MAX && !CYCLE_MAX) TIME_MAX = TIME_MAX_STD;
  if (!MutationRate) MutationRate = MRATE_STD;
  if (!CrossoverRate) CrossoverRate = CRATE_STD;

  std::shared_ptr<ProfileModule> PModule(new ProfileModule(MyModule));
  CostEstimatorOptions Opts = gcl::populatePModule(PModule);

  double EstimatedAccuracy = 1;
  OptAccuracyBaseT OptAccuracyBase;
  CorrectionBaseT CorrectionBase;
  if (!MBasePath.empty() && !ABasePath.empty() && !CBasePath.empty() && !OABasePath.empty()) {
    auto MetricBase = loadMetricsBase(MBasePath);
    auto AccuracyBase = loadAccuracyBase(ABasePath);
    auto NearestMetricName = getNearestMetric(PModule, MetricBase);
    EstimatedAccuracy =
      getAccuracyFor(NearestMetricName, Opts, AccuracyBase);

    CorrectionBase =
      loadCorrectionBase(CBasePath+"/"+NearestMetricName+".estr");
    OptAccuracyBase =
      loadOptAccuracyBase(OABasePath+"/"+NearestMetricName+".ocor");
  }

  int PAPIEvents[1] = {PAPI_TOT_CYC};
  double RealInitCost =
    (GEOS::getPAPIProfile(PModule, ExecutionKind::JIT, PAPIEvents, 1))[0];

  double InitCost;
  if (Randomness)
    InitCost = (rand() % 10) + 1;
  else
    InitCost = GEOS::analyseCost(PModule, Opts);

  int Cycles = 0;
  CompareSolution CompSolVar(EstimatedAccuracy);

  BestSeqT BestSequences((CompareSolution(EstimatedAccuracy)));
  BestSeqT GlobalBest((CompareSolution(EstimatedAccuracy)));
  PopT Population;

  initializePopulation(Population);
  evaluatePopulation(Population, CorrectionBase, OptAccuracyBase,
      BestSequences, PModule, Opts, EstimatedAccuracy);

  time_t Start = time(0);
  while (!isFinished(Start, Cycles)) {
    PopT MatingPool =
      selection(Population, EstimatedAccuracy);
    Population =
      crossover(MatingPool);
    mutation(Population);

    evaluatePopulation(Population, CorrectionBase, OptAccuracyBase,
        BestSequences, PModule, Opts, EstimatedAccuracy);

    BestSeqT Aux((CompareSolution(EstimatedAccuracy)));
    for (unsigned i = 0; i < BSIZE; i++) {
      Aux.push(BestSequences.top());
      BestSequences.pop();
      if (GlobalBest.size()) {
        Aux.push(GlobalBest.top());
        GlobalBest.pop();
      }
    }
    GlobalBest = BestSeqT(CompareSolution(EstimatedAccuracy));
    for (unsigned i = 0; i < BSIZE; i++) {
      GlobalBest.push(Aux.top());
      Aux.pop();
    }
    Cycles += 1;
  }

  double BestRealSpeedUp = 0;
  double BestEstSpeedUp = 0;
  Solution BestSolution;
  while (GlobalBest.size() != 0) {
    auto B = GlobalBest.top();
    auto PO = GEOS::applyPasses(PModule, B.Sequence);
    double RealFinalCost =
      (GEOS::getPAPIProfile(PO, ExecutionKind::JIT, PAPIEvents, 1))[0];
    double FinalCost;

    if (Randomness) FinalCost = (rand() % 10) + 1;
    else FinalCost = GEOS::analyseCost(PO, Opts);

    if ((RealInitCost/RealFinalCost) > BestRealSpeedUp) {
      BestRealSpeedUp = RealInitCost/RealFinalCost;
      BestEstSpeedUp = InitCost/FinalCost;
      BestSolution = B;
    }

    if (Randomness) GlobalBest = BestSeqT();
    else GlobalBest.pop();
  }

  printf("\n%f %f\n", BestEstSpeedUp,
      BestRealSpeedUp);
  return 0;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2014, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/escape_string.hpp" // for from_hex
#include "libtorrent/alert_types.hpp"
#include "libtorrent/bencode.hpp" // for bencode()
#include "libtorrent/kademlia/item.hpp" // for sign_mutable_item
#include "ed25519.h"
#include <boost/bind.hpp>

#include <stdlib.h>

using namespace libtorrent;

void usage()
{
	fprintf(stderr,
		"USAGE:\ndht <command> <arg>\n\nCOMMANDS:\n"
		"get <hash>                - retrieves and prints out the immutable\n"
		"                            item stored under hash.\n"
		"put <string>              - puts the specified string as an immutable\n"
		"                            item onto the DHT. The resulting target hash\n"
		"gen-key <key-file>        - generate ed25519 keypair and save it in\n"
		"                            the specified file\n"
		"mput <key-file> <string>  - puts the specified string as a mutable\n"
		"                            object under the public key in key-file\n"
		"mget <public-key>         - get a mutable object under the specified\n"
		"                            public key\n"
		);
	exit(1);
}

std::auto_ptr<alert> wait_for_alert(session& s, int alert_type)
{
	std::auto_ptr<alert> ret;
	bool found = false;
	while (!found)
	{
		s.wait_for_alert(seconds(5));

		std::deque<alert*> alerts;
		s.pop_alerts(&alerts);
		for (std::deque<alert*>::iterator i = alerts.begin()
			, end(alerts.end()); i != end; ++i)
		{
			if ((*i)->type() != alert_type)
			{
				static int spinner = 0;
				static const char anim[] = {'-', '\\', '|', '/'};
				printf("\r%c", anim[spinner]);
				fflush(stdout);
				spinner = (spinner + 1) & 3;
				//print some alerts?
				delete *i;
				continue;
			}
			ret = std::auto_ptr<alert>(*i);
			found = true;
		}
	}
	printf("\n");
	return ret;
}

void put_string(entry& e, boost::array<char, 64>& sig, boost::uint64_t& seq
	, std::string const& salt, char const* public_key, char const* private_key
	, char const* str)
{
	using libtorrent::dht::sign_mutable_item;

	e = std::string(str);
	std::vector<char> buf;
	bencode(std::back_inserter(buf), e);
	++seq;
	sign_mutable_item(std::pair<char const*, int>(&buf[0], buf.size())
		, std::pair<char const*, int>(&salt[0], salt.size())
		, seq
		, public_key
		, private_key
		, sig.data());
}

void bootstrap(session& s)
{
	printf("bootstrapping\n");
	wait_for_alert(s, dht_bootstrap_alert::alert_type);
}

int main(int argc, char* argv[])
{
	// skip pointer to self
	++argv;
	--argc;

	if (argc < 1) usage();

	if (strcmp(argv[0], "gen-key") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		unsigned char seed[32];
		ed25519_create_seed(seed);

		FILE* f = fopen(argv[0], "wb+");
		if (f == NULL)
		{
			fprintf(stderr, "failed to open file for writing \"%s\": (%d) %s\n"
				, argv[0], errno, strerror(errno));
			return 1;
		}

		fwrite(seed, 1, 32, f);
		fclose(f);
		return 0;
	}

	session s;
	s.set_alert_mask(0xffffffff);

	s.add_dht_router(std::pair<std::string, int>("router.utorrent.com", 6881));

	FILE* f = fopen(".dht", "rb");
	if (f != NULL)
	{
		fseek(f, 0, SEEK_END);
		int size = ftell(f);
		fseek(f, 0, SEEK_SET);
		if (size > 0)
		{
			std::vector<char> state;
			state.resize(size);
			fread(&state[0], 1, state.size(), f);

			lazy_entry e;
			error_code ec;
			lazy_bdecode(&state[0], &state[0] + state.size(), e, ec);
			if (ec)
				fprintf(stderr, "failed to parse .dht file: (%d) %s\n"
					, ec.value(), ec.message().c_str());
			else
				s.load_state(e);
		}
		fclose(f);
	}

	if (strcmp(argv[0], "get") == 0)
	{
		++argv;
		--argc;

		if (argc < 1) usage();

		if (strlen(argv[0]) != 40)
		{
			fprintf(stderr, "the hash is expected to be 40 hex characters\n");
			usage();
		}
		sha1_hash target;
		bool ret = from_hex(argv[0], 40, (char*)&target[0]);
		if (!ret)
		{
			fprintf(stderr, "invalid hex encoding of target hash\n");
			return 1;
		}

		bootstrap(s);
		s.dht_get_item(target);

		printf("GET %s\n", to_hex(target.to_string()).c_str());

		std::auto_ptr<alert> a = wait_for_alert(s, dht_immutable_item_alert::alert_type);

		dht_immutable_item_alert* item = alert_cast<dht_immutable_item_alert>(a.get());
		entry data;
		if (item)
			data.swap(item->item);

		printf("%s", data.to_string().c_str());
	}
	else if (strcmp(argv[0], "put") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		entry data;
		data = std::string(argv[0]);

		bootstrap(s);
		sha1_hash target = s.dht_put_item(data);

		printf("PUT %s\n", to_hex(target.to_string()).c_str());

		wait_for_alert(s, dht_put_alert::alert_type);
	}
	else if (strcmp(argv[0], "mput") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		FILE* f = fopen(argv[0], "rb+");
		if (f == NULL)
		{
			fprintf(stderr, "failed to open file \"%s\": (%d) %s\n"
				, argv[0], errno, strerror(errno));
			return 1;
		}

		unsigned char seed[32];
		fread(seed, 1, 32, f);
		fclose(f);

		++argv;
		--argc;
		if (argc < 1) usage();

		boost::array<char, 32> public_key;
		boost::array<char, 64> private_key;
		ed25519_create_keypair((unsigned char*)public_key.data()
			, (unsigned char*)private_key.data(), seed);

		bootstrap(s);
		s.dht_put_item(public_key, boost::bind(&put_string, _1, _2, _3, _4
			, public_key.data(), private_key.data(), argv[0]));

		printf("public key: %s\n", to_hex(std::string(public_key.data()
			, public_key.size())).c_str());

		wait_for_alert(s, dht_put_alert::alert_type);
		usleep(10000000);
	}
	else if (strcmp(argv[0], "mget") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		int len = strlen(argv[0]);
		if (len != 64)
		{
			fprintf(stderr, "public key is expected to be 64 hex digits\n");
			return 1;
		}
		boost::array<char, 32> public_key;
		bool ret = from_hex(argv[0], len, &public_key[0]);
		if (!ret)
		{
			fprintf(stderr, "invalid hex encoding of public key\n");
			return 1;
		}

		bootstrap(s);
		s.dht_get_item(public_key);

		std::auto_ptr<alert> a = wait_for_alert(s, dht_mutable_item_alert::alert_type);

		dht_mutable_item_alert* item = alert_cast<dht_mutable_item_alert>(a.get());
		entry data;
		if (item)
			data.swap(item->item);

		printf("%s", data.to_string().c_str());
	}
	else
	{
		usage();
	}

	entry e;
	s.save_state(e, session::save_dht_state);
	std::vector<char> state;
	bencode(std::back_inserter(state), e);
	f = fopen(".dht", "wb+");
	if (f == NULL)
	{
		fprintf(stderr, "failed to open file .dht for writing");
		return 1;
	}
	fwrite(&state[0], 1, state.size(), f);
	fclose(f);
}

<commit_msg>fix windows build<commit_after>/*

Copyright (c) 2014, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/escape_string.hpp" // for from_hex
#include "libtorrent/alert_types.hpp"
#include "libtorrent/bencode.hpp" // for bencode()
#include "libtorrent/kademlia/item.hpp" // for sign_mutable_item
#include "ed25519.h"
#include <boost/bind.hpp>

#include <stdlib.h>

using namespace libtorrent;

void usage()
{
	fprintf(stderr,
		"USAGE:\ndht <command> <arg>\n\nCOMMANDS:\n"
		"get <hash>                - retrieves and prints out the immutable\n"
		"                            item stored under hash.\n"
		"put <string>              - puts the specified string as an immutable\n"
		"                            item onto the DHT. The resulting target hash\n"
		"gen-key <key-file>        - generate ed25519 keypair and save it in\n"
		"                            the specified file\n"
		"mput <key-file> <string>  - puts the specified string as a mutable\n"
		"                            object under the public key in key-file\n"
		"mget <public-key>         - get a mutable object under the specified\n"
		"                            public key\n"
		);
	exit(1);
}

std::auto_ptr<alert> wait_for_alert(session& s, int alert_type)
{
	std::auto_ptr<alert> ret;
	bool found = false;
	while (!found)
	{
		s.wait_for_alert(seconds(5));

		std::deque<alert*> alerts;
		s.pop_alerts(&alerts);
		for (std::deque<alert*>::iterator i = alerts.begin()
			, end(alerts.end()); i != end; ++i)
		{
			if ((*i)->type() != alert_type)
			{
				static int spinner = 0;
				static const char anim[] = {'-', '\\', '|', '/'};
				printf("\r%c", anim[spinner]);
				fflush(stdout);
				spinner = (spinner + 1) & 3;
				//print some alerts?
				delete *i;
				continue;
			}
			ret = std::auto_ptr<alert>(*i);
			found = true;
		}
	}
	printf("\n");
	return ret;
}

void put_string(entry& e, boost::array<char, 64>& sig, boost::uint64_t& seq
	, std::string const& salt, char const* public_key, char const* private_key
	, char const* str)
{
	using libtorrent::dht::sign_mutable_item;

	e = std::string(str);
	std::vector<char> buf;
	bencode(std::back_inserter(buf), e);
	++seq;
	sign_mutable_item(std::pair<char const*, int>(&buf[0], buf.size())
		, std::pair<char const*, int>(&salt[0], salt.size())
		, seq
		, public_key
		, private_key
		, sig.data());
}

void bootstrap(session& s)
{
	printf("bootstrapping\n");
	wait_for_alert(s, dht_bootstrap_alert::alert_type);
}

int main(int argc, char* argv[])
{
	// skip pointer to self
	++argv;
	--argc;

	if (argc < 1) usage();

	if (strcmp(argv[0], "gen-key") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		unsigned char seed[32];
		ed25519_create_seed(seed);

		FILE* f = fopen(argv[0], "wb+");
		if (f == NULL)
		{
			fprintf(stderr, "failed to open file for writing \"%s\": (%d) %s\n"
				, argv[0], errno, strerror(errno));
			return 1;
		}

		fwrite(seed, 1, 32, f);
		fclose(f);
		return 0;
	}

	session s;
	s.set_alert_mask(0xffffffff);

	s.add_dht_router(std::pair<std::string, int>("router.utorrent.com", 6881));

	FILE* f = fopen(".dht", "rb");
	if (f != NULL)
	{
		fseek(f, 0, SEEK_END);
		int size = ftell(f);
		fseek(f, 0, SEEK_SET);
		if (size > 0)
		{
			std::vector<char> state;
			state.resize(size);
			fread(&state[0], 1, state.size(), f);

			lazy_entry e;
			error_code ec;
			lazy_bdecode(&state[0], &state[0] + state.size(), e, ec);
			if (ec)
				fprintf(stderr, "failed to parse .dht file: (%d) %s\n"
					, ec.value(), ec.message().c_str());
			else
				s.load_state(e);
		}
		fclose(f);
	}

	if (strcmp(argv[0], "get") == 0)
	{
		++argv;
		--argc;

		if (argc < 1) usage();

		if (strlen(argv[0]) != 40)
		{
			fprintf(stderr, "the hash is expected to be 40 hex characters\n");
			usage();
		}
		sha1_hash target;
		bool ret = from_hex(argv[0], 40, (char*)&target[0]);
		if (!ret)
		{
			fprintf(stderr, "invalid hex encoding of target hash\n");
			return 1;
		}

		bootstrap(s);
		s.dht_get_item(target);

		printf("GET %s\n", to_hex(target.to_string()).c_str());

		std::auto_ptr<alert> a = wait_for_alert(s, dht_immutable_item_alert::alert_type);

		dht_immutable_item_alert* item = alert_cast<dht_immutable_item_alert>(a.get());
		entry data;
		if (item)
			data.swap(item->item);

		printf("%s", data.to_string().c_str());
	}
	else if (strcmp(argv[0], "put") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		entry data;
		data = std::string(argv[0]);

		bootstrap(s);
		sha1_hash target = s.dht_put_item(data);

		printf("PUT %s\n", to_hex(target.to_string()).c_str());

		wait_for_alert(s, dht_put_alert::alert_type);
	}
	else if (strcmp(argv[0], "mput") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		FILE* f = fopen(argv[0], "rb+");
		if (f == NULL)
		{
			fprintf(stderr, "failed to open file \"%s\": (%d) %s\n"
				, argv[0], errno, strerror(errno));
			return 1;
		}

		unsigned char seed[32];
		fread(seed, 1, 32, f);
		fclose(f);

		++argv;
		--argc;
		if (argc < 1) usage();

		boost::array<char, 32> public_key;
		boost::array<char, 64> private_key;
		ed25519_create_keypair((unsigned char*)public_key.data()
			, (unsigned char*)private_key.data(), seed);

		bootstrap(s);
		s.dht_put_item(public_key, boost::bind(&put_string, _1, _2, _3, _4
			, public_key.data(), private_key.data(), argv[0]));

		printf("public key: %s\n", to_hex(std::string(public_key.data()
			, public_key.size())).c_str());

		wait_for_alert(s, dht_put_alert::alert_type);
	}
	else if (strcmp(argv[0], "mget") == 0)
	{
		++argv;
		--argc;
		if (argc < 1) usage();

		int len = strlen(argv[0]);
		if (len != 64)
		{
			fprintf(stderr, "public key is expected to be 64 hex digits\n");
			return 1;
		}
		boost::array<char, 32> public_key;
		bool ret = from_hex(argv[0], len, &public_key[0]);
		if (!ret)
		{
			fprintf(stderr, "invalid hex encoding of public key\n");
			return 1;
		}

		bootstrap(s);
		s.dht_get_item(public_key);

		std::auto_ptr<alert> a = wait_for_alert(s, dht_mutable_item_alert::alert_type);

		dht_mutable_item_alert* item = alert_cast<dht_mutable_item_alert>(a.get());
		entry data;
		if (item)
			data.swap(item->item);

		printf("%s", data.to_string().c_str());
	}
	else
	{
		usage();
	}

	entry e;
	s.save_state(e, session::save_dht_state);
	std::vector<char> state;
	bencode(std::back_inserter(state), e);
	f = fopen(".dht", "wb+");
	if (f == NULL)
	{
		fprintf(stderr, "failed to open file .dht for writing");
		return 1;
	}
	fwrite(&state[0], 1, state.size(), f);
	fclose(f);
}

<|endoftext|>