<commit_before>#include "hxx.hpp"

#include <algorithm>
#include <iostream>
#include <random>
#include <utility>
#include <vector>
using std::cin;
using std::cout;
using std::nth_element;
using std::ranlux48;
using std::swap;
using std::uniform_int_distribution;
using std::vector;

void output_lambda (const hxx_matrices&);

double median (double* p, size_t n)
{
    nth_element (p, p + n/2, p + n);

    if (1 & n) {
        return p[n/2];
    } else {
        double b = p[n/2];
        nth_element (p, p + n/2 - 1, p + n);
        double a = p[n/2 - 1];
        return (a + b)/2.;
    }
}

int main (int argc, char *argv[])
{
    vector<double> raw;

    double d_in;

    while (cin >> d_in) {
        raw.push_back (d_in);
    }

    for (auto i: raw) {
        cout << i << " ";
    }
    cout << "\n";

    size_t T = raw.size ();

    {
        vector<double> raw_copy (raw);

        double m = median (&raw[0], T);

        cout << "Median = " << m << "\n";
    }

    vector<int> O (T);
    ranlux48 eng;
    uniform_int_distribution<size_t> uidst (0, T - 1);

//    vector<int> Q (T);
    vector<double> Gamma, Xi;

    hxx_matrices lambda1 (2, 2), lambda2 (2, 2);
    hxx_matrices* lambda_in = &lambda1;
    hxx_matrices* lambda_out = &lambda2;

    for (int s = 0; s < 10; ++s) {
        double split = raw[uidst (eng)];

        for (int t = 0; t < T; ++t) {
            if (raw[t] < split) {
                O[t] = 0;
            } else {
                O[t] = 1;
            }
        }

        lambda_in->randomize ();
        output_lambda (*lambda_in);
        cout << " split=" << split;
        cout << "\n";

        for (int i = 0; i < 10; ++i) {
            hxx_forwardbackward (O, *lambda_in, Xi, Gamma);

            hxx_baumwelch (O, Xi, Gamma, *lambda_out);

            output_lambda (*lambda_out);

            cout << "\n";

            swap (lambda_in, lambda_out);
        }
    }
}

void output_lambda (const hxx_matrices& lambda) {
    int N = lambda.N ();
    int M = lambda.M ();

    cout << "A = {";
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            cout << " " << lambda.a (i, j);
        }
    }
    cout << " } ";

    cout << "B = {";
    for (int i = 0; i < N; ++i) {
        for (int k = 0; k < M; ++k) {
            cout << " " << lambda.b (i, k);
        }
    }
    cout << " } ";

    cout << "Pi = {";
    for (int i = 0; i < N; ++i) {
        cout << " " << lambda.p (i);
    }
    cout << " } ";
}

<commit_msg>Prepare output for Python.<commit_after>#include "hxx.hpp"

#include <algorithm>
#include <iostream>
#include <random>
#include <utility>
#include <vector>
using std::cin;
using std::cout;
using std::nth_element;
using std::ranlux48;
using std::swap;
using std::uniform_int_distribution;
using std::vector;

void output_lambda (const hxx_matrices&);

double median (double* p, size_t n)
{
    nth_element (p, p + n/2, p + n);

    if (1 & n) {
        return p[n/2];
    } else {
        double b = p[n/2];
        nth_element (p, p + n/2 - 1, p + n);
        double a = p[n/2 - 1];
        return (a + b)/2.;
    }
}

int main (int argc, char *argv[])
{
    vector<double> raw;

    double d_in;

    while (cin >> d_in) {
        raw.push_back (d_in);
    }

    size_t T = raw.size ();

    bool convert_pct = true;

    if (convert_pct) {
        for (int t = 0; t < T - 1; ++t) {
            double prev = raw[t];
            raw[t] = raw[t + 1] / raw[t] - 1.;
        }
        --T;
    }

    for (auto i: raw) {
        cout << i << " ";
    }
    cout << "\n";

    {
        vector<double> raw_copy (raw);

        double m = median (&raw[0], T);

        cout << "Median = " << m << "\n";
    }

    vector<int> O (T);
    ranlux48 eng;
    uniform_int_distribution<size_t> uidst (0, T - 1);

//    vector<int> Q (T);
    vector<double> Gamma, Xi;

    hxx_matrices lambda1 (2, 2), lambda2 (2, 2);
    hxx_matrices* lambda_in = &lambda1;
    hxx_matrices* lambda_out = &lambda2;

    for (int s = 0; s < 10; ++s) {
        double split = raw[uidst (eng)];

        for (int t = 0; t < T; ++t) {
            if (raw[t] < split) {
                O[t] = 0;
            } else {
                O[t] = 1;
            }
        }

        lambda_in->randomize ();
        output_lambda (*lambda_in);
        cout << " split=" << split;
        cout << "\n";

        const int reps = 10;
        for (int i = 0; i < reps; ++i) {
            hxx_forwardbackward (O, *lambda_in, Xi, Gamma);

            hxx_baumwelch (O, Xi, Gamma, *lambda_out);

            if (reps - 1 == i) {
                cout << "'k" << split << "':{";
            }

            output_lambda (*lambda_out);

            if (reps -1 == i) {
                cout << ",'split':" << split << "},";
            }
            cout << "\n";

            swap (lambda_in, lambda_out);
        }
    }
}

void output_lambda (const hxx_matrices& lambda) {
    int N = lambda.N ();
    int M = lambda.M ();

    cout << "'A':[";
    for (int i = 0; i < N; ++i) {
        cout << "[";
        for (int j = 0; j < N; ++j) {
            cout << lambda.a (i, j) << ",";
        }
        cout << "],";
    }
    cout << "],";

    cout << "'B':[";
    for (int i = 0; i < N; ++i) {
        cout << "[";
        for (int k = 0; k < M; ++k) {
            cout << lambda.b (i, k) << ",";
        }
        cout << "],";
    }
    cout << "],";

    cout << "'Pi':[";
    for (int i = 0; i < N; ++i) {
        cout << lambda.p (i) << ",";
    }
    cout << "]";
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

} // namespace unnamed

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			else
				identity << std::string(f->id, f->id+2) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version
				<< "." << (int)f->tag_version;

			return identity.str();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		// ----------------------
		// non standard encodings
		// ----------------------

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.str();
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
		{
			return "Experimental 3.2.1b2";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Experimental 3.1";
		}

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Generic";
		}

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

} // namespace unnamed

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			else
				identity << std::string(f->id, f->id+2) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version
				<< "." << (int)f->tag_version;

			return identity.str();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			else if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		// ----------------------
		// non standard encodings
		// ----------------------

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.str();
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
		{
			return "Experimental 3.2.1b2";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Experimental 3.1";
		}

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Generic";
		}

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*
This file is part of qNotesManager.

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

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

You should have received a copy of the GNU General Public License
along with qNotesManager. If not, see <http://www.gnu.org/licenses/>.
*/

#include "imagedownloader.h"

#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QImageReader>
#include <QNetworkProxy>

using namespace qNotesManager;

ImageDownloader::ImageDownloader(QObject *parent) : QObject(parent), OriginalUrlAttribute((QNetworkRequest::Attribute)1000) {
	manager = new QNetworkAccessManager(this);

	connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
			this, SLOT(sl_netManager_authenticationRequired(QNetworkReply*,QAuthenticator*)), Qt::DirectConnection);
	connect(manager, SIGNAL(finished(QNetworkReply*)),
			this, SLOT(sl_netManager_finished(QNetworkReply*)), Qt::DirectConnection);
	connect(manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
			this, SLOT(sl_netManager_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::DirectConnection);
	connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
			this, SLOT(sl_netManager_sslErrors(QNetworkReply*,QList<QSslError>)), Qt::DirectConnection);

	networkErrorMessages.insert(0,		"QNetworkReply::NoError");
	networkErrorMessages.insert(1,		"QNetworkReply::ConnectionRefusedError");
	networkErrorMessages.insert(2,		"QNetworkReply::RemoteHostClosedError");
	networkErrorMessages.insert(3,		"QNetworkReply::HostNotFoundError");
	networkErrorMessages.insert(4,		"QNetworkReply::TimeoutError");
	networkErrorMessages.insert(5,		"QNetworkReply::OperationCanceledError");
	networkErrorMessages.insert(6,		"QNetworkReply::SslHandshakeFailedError");
	networkErrorMessages.insert(101,	"QNetworkReply::ProxyConnectionRefusedError");
	networkErrorMessages.insert(102,	"QNetworkReply::ProxyConnectionClosedError");
	networkErrorMessages.insert(103,	"QNetworkReply::ProxyNotFoundError");
	networkErrorMessages.insert(104,	"QNetworkReply::ProxyTimeoutError");
	networkErrorMessages.insert(105,	"QNetworkReply::ProxyAuthenticationRequiredError");
	networkErrorMessages.insert(201,	"QNetworkReply::ContentAccessDenied");
	networkErrorMessages.insert(202,	"QNetworkReply::ContentOperationNotPermittedError");
	networkErrorMessages.insert(203,	"QNetworkReply::ContentNotFoundError");
	networkErrorMessages.insert(204,	"QNetworkReply::AuthenticationRequiredError");
	networkErrorMessages.insert(205,	"QNetworkReply::ContentReSendError");
	networkErrorMessages.insert(301,	"QNetworkReply::ProtocolUnknownError");
	networkErrorMessages.insert(302,	"QNetworkReply::ProtocolInvalidOperationError");
	networkErrorMessages.insert(99,		"QNetworkReply::UnknownNetworkError");
	networkErrorMessages.insert(199,	"QNetworkReply::UnknownProxyError");
	networkErrorMessages.insert(299,	"QNetworkReply::UnknownContentError");
	networkErrorMessages.insert(399,	"QNetworkReply::ProtocolFailure");
}

ImageDownloader::~ImageDownloader() {
	CancelAllDownloads();
}

void ImageDownloader::SetProxy(QNetworkProxy& p) {
	manager->setProxy(p);
}

bool ImageDownloader::IsProxyEnabled() const {
	return manager->proxy().type() != QNetworkProxy::NoProxy;
}

void ImageDownloader::DisableProxy() {
	manager->setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
}

void ImageDownloader::Download(QUrl url) {
	if (activeDownloads.contains(url)) {return;}

	QNetworkReply* reply = manager->get(QNetworkRequest(url));

	activeDownloads.insert(url, reply);

	connect(reply, SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(sl_reply_downloadProgress(qint64,qint64)));
}

void ImageDownloader::CancelDownload(QUrl url) {
	if (activeDownloads.contains(url)) {
		activeDownloads[url]->abort();
		activeDownloads.remove(url);
	}
}

void ImageDownloader::CancelAllDownloads() {
	foreach (QUrl url, activeDownloads.keys()) {
		activeDownloads[url]->abort();
		activeDownloads.remove(url);
	}
}

QList<QUrl> ImageDownloader::ActiveDownloads() const {
	return activeDownloads.keys();
}

bool ImageDownloader::HasActiveDownload(const QUrl url) const {
	return activeDownloads.contains(url);
}

void ImageDownloader::sl_reply_downloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
	QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
	Q_ASSERT(reply != 0);

	QUrl url = extractOriginalUrl(reply);
	qint64 progress = 0;

	if (bytesTotal != 0 && bytesReceived != 0){
		progress = (bytesReceived * 100) / bytesTotal;
	}
	emit sg_Progress(url, (int)progress);
}

QUrl ImageDownloader::extractOriginalUrl(QNetworkReply* reply) {
	Q_ASSERT(reply != 0);

	QUrl originalRequestUrl = reply->request().attribute(OriginalUrlAttribute).isValid() ?
				reply->request().attribute(OriginalUrlAttribute).toUrl() :
				reply->request().url();

	return originalRequestUrl;
}

void ImageDownloader::sl_netManager_finished (QNetworkReply * reply) {
	QUrl currentReplyUrl = reply->url();
	QUrl originalRequestUrl = extractOriginalUrl(reply);

	// Pring reply info
	qDebug() << "\nDownload finished";
	qDebug() << "Reply size: " << reply->size();
	qDebug() << "Reply url: " << reply->url().toString();
	qDebug() << "Reply isFinished: " << reply->isFinished() << "\n";

	QNetworkReply::NetworkError error = reply->error();
	if (error != QNetworkReply::NoError) {
		qDebug() << "ERROR: Cannot load file: " << reply->request().url().toString();
		downloadFailed(originalRequestUrl, "Cannot download file. Error type: " + networkErrorMessages[error]);
		disconnectAndDeleteReply(reply);
		return;
	} else {
		qDebug() << "Reply: No errors";
	}

	QVariant atr = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
	if (atr.isValid() && !atr.toString().isEmpty()) {
		qDebug() << "Redirect to: " << atr.toString();

		QNetworkRequest request = QNetworkRequest(atr.toUrl());
		// In case of redirect put original url into OriginalUrlAttribute of new request
		request.setAttribute(OriginalUrlAttribute, originalRequestUrl);

		QNetworkReply* newReply = manager->get(request);
		activeDownloads[originalRequestUrl] = newReply;
		connect(newReply, SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(sl_reply_downloadProgress(qint64,qint64)));
		disconnectAndDeleteReply(reply);
		return;
	} else {
		qDebug() << "No redirect";
	}

	qDebug() << "currentReplyUrl: " << currentReplyUrl.toString();
	qDebug() << "originalRequestUrl: " << originalRequestUrl.toString();

	// Detect image type
	QByteArray fileSuffix;
	{
		// Try to read image type from reply's ContentTypeHeader
		if (fileSuffix.isEmpty()) {
			QVariant v = reply->header(QNetworkRequest::ContentTypeHeader);
			if (v.isValid()) {
				QString data = v.toString().toLower();
				QString s1 = data.mid(0, 6);
				QString s2 = data.mid(6, data.length() - 6);

				if (s1.isNull() || s1.isEmpty() || s1 != "image/") {
					downloadFailed(originalRequestUrl, "Downloaded data is not an image. Header:" + v.toString());

					// To check what was returned
					QFile file("lastFile");
					file.open(QIODevice::WriteOnly | QIODevice::Truncate);
					file.write(reply->readAll());
					file.close();
					qDebug() << "Data saved in file 'lastFile' for inspection";

					disconnectAndDeleteReply(reply);
					return;
				}

				if (!s1.isNull() && !s1.isEmpty() && s1 == "image/" && !s2.isNull() && !s2.isEmpty()) {
					fileSuffix = s2.toLatin1();
					qDebug() << "Filetype detected from reply content type header";
				}
			}
		}

		// Try to detect image type from url:
		if (fileSuffix.isEmpty()) {
			QFileInfo info(currentReplyUrl.toString());
			if (!info.suffix().isEmpty()) {
				fileSuffix = info.suffix().toLower().toLatin1();
				qDebug() << "Filetype detected from reply URL";
			}
		}

		// Otherwise try to read it from reply's location header
		if (fileSuffix.isEmpty()) {
			QVariant v = reply->header(QNetworkRequest::LocationHeader);
			if (v.isValid()) {
				QFileInfo info = QFileInfo(v.toString());
				if (!info.suffix().isEmpty()) {
					fileSuffix = info.suffix().toLower().toLatin1();
					qDebug() << "Filetype detected from reply location header";
				}
			}
		}
		qDebug() << "Recognized file suffix: " << fileSuffix;
	}

	if ((fileSuffix.isEmpty())
		 ||
		 ((!fileSuffix.isEmpty()) && (!QImageReader::supportedImageFormats().contains(fileSuffix)))) {
		// If suffix is empty or suffix is not empty, but Qt doesn't support this file type
		qDebug() << "ERROR: Unknown or unsupported file type";
		{
			// To check what was returned
			QFile file("lastFile");
			file.open(QIODevice::WriteOnly | QIODevice::Truncate);
			file.write(reply->readAll());
			file.close();
			qDebug() << "Data saved in file 'lastFile' for inspection";
		}
		downloadFailed(originalRequestUrl, "Unknown or unsupported file type");
		disconnectAndDeleteReply(reply);
		return;
	}

	QByteArray replyData = reply->readAll();
	QImage image = QImage::fromData(replyData, fileSuffix.data());
	if (image.isNull()) {

		{	// To check what was returned
			QFile file("lastFile");
			file.open(QIODevice::WriteOnly | QIODevice::Truncate);
			file.write(replyData);
			file.close();
		}

		qDebug() << "ERROR: Unable to load image";
		downloadFailed(originalRequestUrl, "Unable to load image");
		disconnectAndDeleteReply(reply);
		return;
	}

	image.setText("FORMAT", fileSuffix.data());

	activeDownloads.remove(originalRequestUrl);
	emit sg_DownloadFinished(originalRequestUrl, image);
	disconnectAndDeleteReply(reply);
}

void ImageDownloader::disconnectAndDeleteReply(QNetworkReply* reply) {
	Q_ASSERT(reply != 0);
	reply->disconnect();
	reply->deleteLater();
}

void ImageDownloader::downloadFailed(QUrl url, QString message) {
	activeDownloads.remove(url);
	emit sg_DownloadError(url, message);
}

void ImageDownloader::downloadSucceded(QUrl) {

}

void ImageDownloader::sl_netManager_authenticationRequired (QNetworkReply*, QAuthenticator*) {
	qDebug() << "[sl_netManager_authenticationRequired]";
}

void ImageDownloader::sl_netManager_proxyAuthenticationRequired (const QNetworkProxy&, QAuthenticator*) {
	qDebug() << "[sl_netManager_proxyAuthenticationRequired]";
}

void ImageDownloader::sl_netManager_sslErrors (QNetworkReply*, const QList<QSslError>&) {
	qDebug() << "[sl_netManager_sslErrors] SslError :";
	//for (int i = 0; i < errors.size(); ++i) {
	//	qDebug() << "\t\t" << sslError[errors[i].error()];
	//}
}
<commit_msg>Fixed image loading mechanism: if image format in http header is wrong, Qt will try to determine image format\nUnknown images can be saved to disk in Debug mode only now<commit_after>/*
This file is part of qNotesManager.

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

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

You should have received a copy of the GNU General Public License
along with qNotesManager. If not, see <http://www.gnu.org/licenses/>.
*/

#include "imagedownloader.h"

#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QImageReader>
#include <QNetworkProxy>

using namespace qNotesManager;

ImageDownloader::ImageDownloader(QObject *parent) : QObject(parent), OriginalUrlAttribute((QNetworkRequest::Attribute)1000) {
	manager = new QNetworkAccessManager(this);

	connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
			this, SLOT(sl_netManager_authenticationRequired(QNetworkReply*,QAuthenticator*)), Qt::DirectConnection);
	connect(manager, SIGNAL(finished(QNetworkReply*)),
			this, SLOT(sl_netManager_finished(QNetworkReply*)), Qt::DirectConnection);
	connect(manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
			this, SLOT(sl_netManager_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::DirectConnection);
	connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
			this, SLOT(sl_netManager_sslErrors(QNetworkReply*,QList<QSslError>)), Qt::DirectConnection);

	networkErrorMessages.insert(0,		"QNetworkReply::NoError");
	networkErrorMessages.insert(1,		"QNetworkReply::ConnectionRefusedError");
	networkErrorMessages.insert(2,		"QNetworkReply::RemoteHostClosedError");
	networkErrorMessages.insert(3,		"QNetworkReply::HostNotFoundError");
	networkErrorMessages.insert(4,		"QNetworkReply::TimeoutError");
	networkErrorMessages.insert(5,		"QNetworkReply::OperationCanceledError");
	networkErrorMessages.insert(6,		"QNetworkReply::SslHandshakeFailedError");
	networkErrorMessages.insert(101,	"QNetworkReply::ProxyConnectionRefusedError");
	networkErrorMessages.insert(102,	"QNetworkReply::ProxyConnectionClosedError");
	networkErrorMessages.insert(103,	"QNetworkReply::ProxyNotFoundError");
	networkErrorMessages.insert(104,	"QNetworkReply::ProxyTimeoutError");
	networkErrorMessages.insert(105,	"QNetworkReply::ProxyAuthenticationRequiredError");
	networkErrorMessages.insert(201,	"QNetworkReply::ContentAccessDenied");
	networkErrorMessages.insert(202,	"QNetworkReply::ContentOperationNotPermittedError");
	networkErrorMessages.insert(203,	"QNetworkReply::ContentNotFoundError");
	networkErrorMessages.insert(204,	"QNetworkReply::AuthenticationRequiredError");
	networkErrorMessages.insert(205,	"QNetworkReply::ContentReSendError");
	networkErrorMessages.insert(301,	"QNetworkReply::ProtocolUnknownError");
	networkErrorMessages.insert(302,	"QNetworkReply::ProtocolInvalidOperationError");
	networkErrorMessages.insert(99,		"QNetworkReply::UnknownNetworkError");
	networkErrorMessages.insert(199,	"QNetworkReply::UnknownProxyError");
	networkErrorMessages.insert(299,	"QNetworkReply::UnknownContentError");
	networkErrorMessages.insert(399,	"QNetworkReply::ProtocolFailure");
}

ImageDownloader::~ImageDownloader() {
	CancelAllDownloads();
}

void ImageDownloader::SetProxy(QNetworkProxy& p) {
	manager->setProxy(p);
}

bool ImageDownloader::IsProxyEnabled() const {
	return manager->proxy().type() != QNetworkProxy::NoProxy;
}

void ImageDownloader::DisableProxy() {
	manager->setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
}

void ImageDownloader::Download(QUrl url) {
	if (activeDownloads.contains(url)) {return;}

	QNetworkReply* reply = manager->get(QNetworkRequest(url));

	activeDownloads.insert(url, reply);

	connect(reply, SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(sl_reply_downloadProgress(qint64,qint64)));
}

void ImageDownloader::CancelDownload(QUrl url) {
	if (activeDownloads.contains(url)) {
		activeDownloads[url]->abort();
		activeDownloads.remove(url);
	}
}

void ImageDownloader::CancelAllDownloads() {
	foreach (QUrl url, activeDownloads.keys()) {
		activeDownloads[url]->abort();
		activeDownloads.remove(url);
	}
}

QList<QUrl> ImageDownloader::ActiveDownloads() const {
	return activeDownloads.keys();
}

bool ImageDownloader::HasActiveDownload(const QUrl url) const {
	return activeDownloads.contains(url);
}

void ImageDownloader::sl_reply_downloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
	QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
	Q_ASSERT(reply != 0);

	QUrl url = extractOriginalUrl(reply);
	qint64 progress = 0;

	if (bytesTotal != 0 && bytesReceived != 0){
		progress = (bytesReceived * 100) / bytesTotal;
	}
	emit sg_Progress(url, (int)progress);
}

QUrl ImageDownloader::extractOriginalUrl(QNetworkReply* reply) {
	Q_ASSERT(reply != 0);

	QUrl originalRequestUrl = reply->request().attribute(OriginalUrlAttribute).isValid() ?
				reply->request().attribute(OriginalUrlAttribute).toUrl() :
				reply->request().url();

	return originalRequestUrl;
}

void ImageDownloader::sl_netManager_finished (QNetworkReply * reply) {
	QUrl currentReplyUrl = reply->url();
	QUrl originalRequestUrl = extractOriginalUrl(reply);

	// Pring reply info
	qDebug() << "\nDownload finished";
	qDebug() << "Reply size: " << reply->size();
	qDebug() << "Reply url: " << reply->url().toString();
	qDebug() << "Reply isFinished: " << reply->isFinished() << "\n";

	QNetworkReply::NetworkError error = reply->error();
	if (error != QNetworkReply::NoError) {
		qDebug() << "ERROR: Cannot load file: " << reply->request().url().toString();
		downloadFailed(originalRequestUrl, "Cannot download file. Error type: " + networkErrorMessages[error]);
		disconnectAndDeleteReply(reply);
		return;
	} else {
		qDebug() << "Reply: No errors";
	}

	QVariant atr = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
	if (atr.isValid() && !atr.toString().isEmpty()) {
		qDebug() << "Redirect to: " << atr.toString();

		QNetworkRequest request = QNetworkRequest(atr.toUrl());
		// In case of redirect put original url into OriginalUrlAttribute of new request
		request.setAttribute(OriginalUrlAttribute, originalRequestUrl);

		QNetworkReply* newReply = manager->get(request);
		activeDownloads[originalRequestUrl] = newReply;
		connect(newReply, SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(sl_reply_downloadProgress(qint64,qint64)));
		disconnectAndDeleteReply(reply);
		return;
	} else {
		qDebug() << "No redirect";
	}

	qDebug() << "currentReplyUrl: " << currentReplyUrl.toString();
	qDebug() << "originalRequestUrl: " << originalRequestUrl.toString();

	// Detect image type
	QByteArray fileSuffix;
	{
		// Try to read image type from reply's ContentTypeHeader
		if (fileSuffix.isEmpty()) {
			QVariant v = reply->header(QNetworkRequest::ContentTypeHeader);
			if (v.isValid()) {
				QString data = v.toString().toLower();
				QString s1 = data.mid(0, 6);
				QString s2 = data.mid(6, data.length() - 6);

				if (s1.isNull() || s1.isEmpty() || s1 != "image/") {
					downloadFailed(originalRequestUrl, "Downloaded data is not an image. Header:" + v.toString());
#ifdef DEBUG
					// To check what was returned
					QFile file("lastFile");
					file.open(QIODevice::WriteOnly | QIODevice::Truncate);
					file.write(reply->readAll());
					file.close();
					qDebug() << "Data saved in file 'lastFile' for inspection";
#endif

					disconnectAndDeleteReply(reply);
					return;
				}

				if (!s1.isNull() && !s1.isEmpty() && s1 == "image/" && !s2.isNull() && !s2.isEmpty()) {
					fileSuffix = s2.toLatin1();
					qDebug() << "Filetype detected from reply content type header";
				}
			}
		}

		// Try to detect image type from url:
		if (fileSuffix.isEmpty()) {
			QFileInfo info(currentReplyUrl.toString());
			if (!info.suffix().isEmpty()) {
				fileSuffix = info.suffix().toLower().toLatin1();
				qDebug() << "Filetype detected from reply URL";
			}
		}

		// Otherwise try to read it from reply's location header
		if (fileSuffix.isEmpty()) {
			QVariant v = reply->header(QNetworkRequest::LocationHeader);
			if (v.isValid()) {
				QFileInfo info = QFileInfo(v.toString());
				if (!info.suffix().isEmpty()) {
					fileSuffix = info.suffix().toLower().toLatin1();
					qDebug() << "Filetype detected from reply location header";
				}
			}
		}
		qDebug() << "Recognized file suffix: " << fileSuffix;
	}

	if ((fileSuffix.isEmpty())
		 ||
		 ((!fileSuffix.isEmpty()) && (!QImageReader::supportedImageFormats().contains(fileSuffix)))) {
		// If suffix is empty or suffix is not empty, but Qt doesn't support this file type
		qDebug() << "ERROR: Unknown or unsupported file type";
#ifdef DEBUG
			// To check what was returned
			QFile file("lastFile");
			file.open(QIODevice::WriteOnly | QIODevice::Truncate);
			file.write(reply->readAll());
			file.close();
			qDebug() << "Data saved in file 'lastFile' for inspection";
#endif
		downloadFailed(originalRequestUrl, "Unknown or unsupported file type");
		disconnectAndDeleteReply(reply);
		return;
	}

	QByteArray replyData = reply->readAll();
	QImage image;
	image = QImage::fromData(replyData, fileSuffix.data());
	if (image.isNull()) {
		// If image was not loaded, let QImage class to determine image's format
		image = QImage::fromData(replyData);
		if (image.isNull()) {
#ifdef DEBUG
				// To check what was returned
				QFile file("lastFile");
				file.open(QIODevice::WriteOnly | QIODevice::Truncate);
				file.write(replyData);
				file.close();
				qDebug() << "Data saved in file 'lastFile' for inspection";
#endif

			qDebug() << "ERROR: Unable to load image";
			downloadFailed(originalRequestUrl, "Unable to load image");
			disconnectAndDeleteReply(reply);
			return;
		}
		fileSuffix = "PNG"; // use PNG format to store unknown images
	}

	image.setText("FORMAT", fileSuffix.data());

	activeDownloads.remove(originalRequestUrl);
	emit sg_DownloadFinished(originalRequestUrl, image);
	disconnectAndDeleteReply(reply);
}

void ImageDownloader::disconnectAndDeleteReply(QNetworkReply* reply) {
	Q_ASSERT(reply != 0);
	reply->disconnect();
	reply->deleteLater();
}

void ImageDownloader::downloadFailed(QUrl url, QString message) {
	activeDownloads.remove(url);
	emit sg_DownloadError(url, message);
}

void ImageDownloader::downloadSucceded(QUrl) {

}

void ImageDownloader::sl_netManager_authenticationRequired (QNetworkReply*, QAuthenticator*) {
	qDebug() << "[sl_netManager_authenticationRequired]";
}

void ImageDownloader::sl_netManager_proxyAuthenticationRequired (const QNetworkProxy&, QAuthenticator*) {
	qDebug() << "[sl_netManager_proxyAuthenticationRequired]";
}

void ImageDownloader::sl_netManager_sslErrors (QNetworkReply*, const QList<QSslError>&) {
	qDebug() << "[sl_netManager_sslErrors] SslError :";
	//for (int i = 0; i < errors.size(); ++i) {
	//	qDebug() << "\t\t" << sslError[errors[i].error()];
	//}
}
<|endoftext|>


<commit_before>//
//  inpal_algorithm.cpp
//  Inverse Palindrome Library
//
//  Created by Bryan Triana on 7/22/16.
//  Copyright © 2016 Inverse Palindrome. All rights reserved.
//

#include "inpal_algorithm.hpp"

std::size_t inpal::algorithm::gcd(std::size_t a, std::size_t b)
{
  while(b!=0)
  {
      std::size_t r = a%b;
      a=b;
      b=r;
  }

    return a;
}

std::size_t inpal::algorithm::modulo(std::size_t a, std::size_t b, std::size_t c)
{
    std::size_t x = 1;

    while(b>0)
    {
        if(b%2==1) x=(x*a%c);
        a=(a*a)%c;
        b/=2;
    }

    return x%c;
}

std::size_t inpal::algorithm::mulmod(std::size_t a, std::size_t b, std::size_t c)
{
    std::size_t x = 0;
    std::size_t y = a%c;

    while(b>0)
    {
        if(b%2==1) x=(x+y)%c;
        y=(y*2)%c;
        b/=2;
    }

    return x%c;
}

std::size_t inpal::algorithm::pollard_rho(std::size_t num)
{
    const std::size_t m = 1000;
    std::size_t a, x, y, ys, r, q, d;

    do a = rand()%num;
    while(a==0||a==num-2);

    y = rand()%num;
    d = 1;
    q = 1;
    r = 1;

    do
    {
        x=y;
        for(std::size_t i=0; i<=r; i++) y=mulmod(y,a,num);
        std::size_t j = 0;

        do
        {
            ys = y;
            for(std::size_t i=0; i<=std::min(m, r-j); i++)
            {
                y=mulmod(y,a,num);
                q *= (std::max(x,y)-std::min(x,y))%num;
            }
            d=gcd(q,num);
            j+=m;
        }
        while(j<r && d==1);
        r*=2;
    }
    while(d==1);

    if(d==num)
    {
        do
        {
            ys=mulmod(ys,a,num);
            d=gcd(std::max(x, ys)-std::min(x,ys), num);
        }
        while(d==1);
    }

    return d;
}

std::vector<std::size_t> inpal::algorithm::trial_division(std::size_t num)
{
    std::vector<std::size_t> p_fac;
    std::size_t prime_factor = 2;

    //trial division
    while(prime_factor<=num)
    {
        if(num%prime_factor==0)
        {
            p_fac.push_back(prime_factor);
            num=num/prime_factor;
        }
        prime_factor += prime_factor==2 ? 1 : 2;
    }

    return p_fac;
}

bool inpal::algorithm::pal_test(std::size_t num)
{
    std::string rev = std::to_string(num);

    //checks if half the reverse of rev is equal to the other half of rev
    if(std::equal(rev.begin(), rev.begin()+rev.size()/2, rev.rbegin()))
    {
        return true;
    }

    return false;
}

<commit_msg>Update inpal_algorithm.cpp<commit_after>//
//  inpal_algorithm.cpp
//  Inverse Palindrome Library
//
//  Created by Bryan Triana on 7/22/16.
//  Copyright © 2016 Inverse Palindrome. All rights reserved.
//

#include "inpal_algorithm.hpp"

std::size_t inpal::algorithm::gcd(std::size_t a, std::size_t b)
{
  while(b!=0)
  {
      std::size_t r = a%b;
      a=b;
      b=r;
  }

    return a;
}

std::size_t inpal::algorithm::modulo(std::size_t a, std::size_t b, std::size_t c)
{
    std::size_t x = 1;

    while(b>0)
    {
        if(b%2==1) x=(x*a%c);
        a=(a*a)%c;
        b/=2;
    }

    return x%c;
}

std::size_t inpal::algorithm::mulmod(std::size_t a, std::size_t b, std::size_t c)
{
    std::size_t x = 0;
    std::size_t y = a%c;

    while(b>0)
    {
        if(b%2==1) x=(x+y)%c;
        y=(y*2)%c;
        b/=2;
    }

    return x%c;
}

std::size_t inpal::algorithm::pollard_rho(std::size_t num)
{
    const std::size_t m = 1000;
    std::size_t a, x, y, ys, r, q, d;

    do a = rand()%num;
    while(a==0||a==num-2);

    y = rand()%num;
    d = 1;
    q = 1;
    r = 1;

    do
    {
        x=y;
        for(std::size_t i=0; i<=r; i++) y=mulmod(y,a,num);
        std::size_t j = 0;

        do
        {
            ys = y;
            for(std::size_t i=0; i<=std::min(m, r-j); i++)
            {
                y=mulmod(y,a,num);
                q *= (std::max(x,y)-std::min(x,y))%num;
            }
            d=gcd(q,num);
            j+=m;
        }
        while(j<r && d==1);
        r*=2;
    }
    while(d==1);

    if(d==num)
    {
        do
        {
            ys=mulmod(ys,a,num);
            d=gcd(std::max(x, ys)-std::min(x,ys), num);
        }
        while(d==1);
    }

    return d;
}

std::vector<std::size_t> inpal::algorithm::trial_division(std::size_t num)
{
    std::vector<std::size_t> p_fac;
    std::size_t prime_factor = 2;

    while(prime_factor<=num)
    {
        if(num%prime_factor==0)
        {
            p_fac.push_back(prime_factor);
            num=num/prime_factor;
        }
        prime_factor += prime_factor==2 ? 1 : 2;
    }

    return p_fac;
}

bool inpal::algorithm::pal_test(std::size_t num)
{
    std::string rev = std::to_string(num);

    //checks if half the reverse of rev is equal to the other half of rev
    if(std::equal(rev.begin(), rev.begin()+rev.size()/2, rev.rbegin()))
    {
        return true;
    }

    return false;
}

<|endoftext|>


<commit_before>/*****************************************************************************\
 *                        ANALYSIS PERFORMANCE TOOLS                         *
 *                               libparaver-api                              *
 *                       Paraver Main Computing Library                      *
 *****************************************************************************
 *     ___     This library is free software; you can redistribute it and/or *
 *    /  __         modify it under the terms of the GNU LGPL as published   *
 *   /  /  _____    by the Free Software Foundation; either version 2.1      *
 *  /  /  /     \   of the License, or (at your option) any later version.   *
 * (  (  ( B S C )                                                           *
 *  \  \  \_____/   This library is distributed in 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 LGPL for more details.   *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public License  *
 * along with this library; if not, write to the Free Software Foundation,   *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA          *
 * The GNU LEsser General Public License is contained in the file COPYING.   *
 *                                 ---------                                 *
 *   Barcelona Supercomputing Center - Centro Nacional de Supercomputacion   *
\*****************************************************************************/

#include "kwindow.h"
#include "intervalderived.h"

KRecordList *IntervalDerived::init( TRecordTime initialTime, TCreateList create,
                                   KRecordList *displayList )
{
  TRecordTime myInitTime;
  info.values.clear();
  info.callingInterval = this;

  createList = create;
  currentValue = 0.0;

  if ( displayList == NULL )
  {
    displayList = &myDisplayList;
    displayList->clear();
  }

  function = ( SemanticDerived * ) window->getSemanticFunction( level );

  setChilds();

  if ( begin != NULL )
  {
    delete begin;
    begin = NULL;
  }
  if ( end != NULL )
  {
    delete end;
    end = NULL;
  }

  if ( function->getInitFromBegin() )
    myInitTime = 0.0;
  else
    myInitTime = initialTime;

  info.callingInterval = this;

  for ( TObjectOrder i = 0; i < childIntervals.size(); i++ )
  {
    childIntervals[ i ]->init( myInitTime, createList, displayList );

    if ( begin == NULL ||
         childIntervals[ i ]->getBegin()->getTime() > begin->getTime() )
    {
      if ( begin != NULL )
        delete begin;
      begin = childIntervals[ i ]->getBegin()->clone();
    }

    if ( end == NULL ||
         childIntervals[ i ]->getEnd()->getTime() < end->getTime() )
    {
      if ( end != NULL )
        delete end;
      end = childIntervals[ i ]->getEnd()->clone();
    }

    info.values.push_back( childIntervals[ i ]->getValue() *
                           window->getFactor( i ) );
  }
  info.dataBeginTime = childIntervals[ 1 ]->getBegin()->getTime();
  currentValue = function->execute( &info );

  while ( end->getTime() < initialTime )
    calcNext( displayList );

  return displayList;
}

KRecordList *IntervalDerived::calcNext( KRecordList *displayList, bool initCalc )
{
  info.values.clear();

  if ( displayList == NULL )
    displayList = &myDisplayList;

  if ( begin != NULL )
    delete begin;
  begin = end->clone();

  if ( end != NULL )
  {
    delete end;
    end = NULL;
  }

  for ( TObjectOrder i = 0; i < childIntervals.size(); ++i )
  {
    if ( childIntervals[ i ]->getEnd()->getTime() <= begin->getTime() )
      childIntervals[ i ]->calcNext( displayList );

    if ( ( end == NULL
           && childIntervals[ i ]->getEnd()->getTime() < childIntervals[ i ]->getWindow()->getTrace()->getEndTime() )
         ||
         ( end != NULL
           && childIntervals[ i ]->getEnd()->getTime() < end->getTime()
           && childIntervals[ i ]->getEnd()->getTime() < childIntervals[ i ]->getWindow()->getTrace()->getEndTime() )
        )
    {
      if ( end != NULL )
        delete end;
      end = childIntervals[ i ]->getEnd()->clone();
    }

    info.values.push_back( childIntervals[ i ]->getValue() *
                           window->getFactor( i ) );
  }
  if( end == NULL )
    end = ( (KTrace *)window->getTrace() )->end();

  info.dataBeginTime = childIntervals[ 0 ]->getBegin()->getTime();
  currentValue = function->execute( &info );

  return displayList;
}

KRecordList *IntervalDerived::calcPrev( KRecordList *displayList, bool initCalc )
{
  info.values.clear();

  if ( displayList == NULL )
    displayList = &myDisplayList;

  if ( end != NULL )
    delete end;
  end = begin->clone();

  if ( begin != NULL )
  {
    delete begin;
    begin = NULL;
  }

  for ( TObjectOrder i = 0; i < childIntervals.size(); i++ )
  {
    if ( childIntervals[ i ]->getBegin()->getTime() >= end->getTime() )
      childIntervals[ i ]->calcPrev( displayList );

    if ( begin == NULL ||
         childIntervals[ i ]->getBegin()->getTime() > begin->getTime() )
    {
      if ( begin != NULL )
        delete begin;
      begin = childIntervals[ i ]->getBegin()->clone();
    }

    info.values.push_back( childIntervals[ i ]->getValue() *
                           window->getFactor( i ) );
  }

  info.dataBeginTime = childIntervals[ 0 ]->getBegin()->getTime();
  currentValue = function->execute( &info );

  return displayList;
}

TWindowLevel IntervalDerived::getWindowLevel() const
{
  return window->getLevel();
}

Interval *IntervalDerived::getWindowInterval( TWindowLevel whichLevel,
    TObjectOrder whichOrder )
{
  return window->getLevelInterval( whichLevel, whichOrder );
}

bool IntervalDerived::IsDerivedWindow() const
{
  return window->isDerivedWindow();
}

TWindowLevel IntervalDerived::getComposeLevel( TWindowLevel whichLevel ) const
{
  return window->getComposeLevel( whichLevel );
}

KTrace *IntervalDerived::getWindowTrace() const
{
  return (KTrace*)window->getTrace();
}

void IntervalDerived::setChilds()
{
  KWindow *window1;
  KWindow *window2;
  TApplOrder tmpAppl;
  TTaskOrder tmpTask;
  TThreadOrder tmpThread;
  TNodeOrder tmpNode;
  TCPUOrder tmpCPU;

  childIntervals.clear();

  if ( window->getParent( 0 )->getLevel() >= window->getParent( 1 )->getLevel() )
  {
    window1 = (KWindow *) window->getParent( 0 );
    window2 = (KWindow *) window->getParent( 1 );
  }
  else
  {
    window1 = (KWindow *) window->getParent( 1 );
    window2 = (KWindow *) window->getParent( 0 );
  }

  if ( window1->getLevel() == APPLICATION )
  {
    tmpAppl = order;
  }
  else if ( window1->getLevel() == TASK )
  {
    window1->getTrace()->getTaskLocation( order, tmpAppl, tmpTask );
  }
  else if ( window1->getLevel() == THREAD )
  {
    window1->getTrace()->getThreadLocation( order, tmpAppl, tmpTask, tmpThread );
  }
  else if ( window1->getLevel() == NODE )
  {
    tmpNode = order;
  }
  else if ( window1->getLevel() == CPU )
  {
    window1->getTrace()->getCPULocation( order, tmpNode, tmpCPU );
  }

  childIntervals.push_back( window1->getLevelInterval( TOPCOMPOSE1, order, true ) );

  if ( window2->getLevel() == WORKLOAD )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, 0, true ) );
  }
  else if ( window2->getLevel() == APPLICATION )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, tmpAppl, true ) );
  }
  else if ( window2->getLevel() == TASK )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1,
                              window2->getTrace()->getGlobalTask( tmpAppl, tmpTask ), true ) );
  }
  else if ( window2->getLevel() == THREAD )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1,
                              window2->getTrace()->getGlobalThread( tmpAppl, tmpTask, tmpThread ), true ) );
  }
  else if ( window2->getLevel() == SYSTEM )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, 0, true ) );
  }
  else if ( window2->getLevel() == NODE )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, tmpNode, true ) );
  }
  else if ( window2->getLevel() == CPU )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1,
                              window2->getTrace()->getGlobalCPU( tmpNode, tmpCPU ), true ) );
  }
}
<commit_msg>BUG Derived window now applies factor using  semval/1/factor if 0.0 < factor < 1.0<commit_after>/*****************************************************************************\
 *                        ANALYSIS PERFORMANCE TOOLS                         *
 *                               libparaver-api                              *
 *                       Paraver Main Computing Library                      *
 *****************************************************************************
 *     ___     This library is free software; you can redistribute it and/or *
 *    /  __         modify it under the terms of the GNU LGPL as published   *
 *   /  /  _____    by the Free Software Foundation; either version 2.1      *
 *  /  /  /     \   of the License, or (at your option) any later version.   *
 * (  (  ( B S C )                                                           *
 *  \  \  \_____/   This library is distributed in 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 LGPL for more details.   *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public License  *
 * along with this library; if not, write to the Free Software Foundation,   *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA          *
 * The GNU LEsser General Public License is contained in the file COPYING.   *
 *                                 ---------                                 *
 *   Barcelona Supercomputing Center - Centro Nacional de Supercomputacion   *
\*****************************************************************************/

#include "kwindow.h"
#include "intervalderived.h"

KRecordList *IntervalDerived::init( TRecordTime initialTime, TCreateList create,
                                   KRecordList *displayList )
{
  TRecordTime myInitTime;
  info.values.clear();
  info.callingInterval = this;

  createList = create;
  currentValue = 0.0;

  if ( displayList == NULL )
  {
    displayList = &myDisplayList;
    displayList->clear();
  }

  function = ( SemanticDerived * ) window->getSemanticFunction( level );

  setChilds();

  if ( begin != NULL )
  {
    delete begin;
    begin = NULL;
  }
  if ( end != NULL )
  {
    delete end;
    end = NULL;
  }

  if ( function->getInitFromBegin() )
    myInitTime = 0.0;
  else
    myInitTime = initialTime;

  info.callingInterval = this;

  for ( TObjectOrder i = 0; i < childIntervals.size(); i++ )
  {
    childIntervals[ i ]->init( myInitTime, createList, displayList );

    if ( begin == NULL ||
         childIntervals[ i ]->getBegin()->getTime() > begin->getTime() )
    {
      if ( begin != NULL )
        delete begin;
      begin = childIntervals[ i ]->getBegin()->clone();
    }

    if ( end == NULL ||
         childIntervals[ i ]->getEnd()->getTime() < end->getTime() )
    {
      if ( end != NULL )
        delete end;
      end = childIntervals[ i ]->getEnd()->clone();
    }

    // Apply factor
    double tmpAbsFactor = fabs( window->getFactor( i ) );
    if ( tmpAbsFactor < 1.0 )
    {
      if ( window->getFactor( i ) < 0.0 )
        info.values.push_back( -childIntervals[ i ]->getValue() / ( 1.0 / tmpAbsFactor ) );
      else
        info.values.push_back( childIntervals[ i ]->getValue() / ( 1.0 / tmpAbsFactor ) );
    }
    else
      info.values.push_back( childIntervals[ i ]->getValue() * window->getFactor( i ) );
  }

  info.dataBeginTime = childIntervals[ 1 ]->getBegin()->getTime();
  currentValue = function->execute( &info );

  while ( end->getTime() < initialTime )
    calcNext( displayList );

  return displayList;
}

KRecordList *IntervalDerived::calcNext( KRecordList *displayList, bool initCalc )
{
  info.values.clear();

  if ( displayList == NULL )
    displayList = &myDisplayList;

  if ( begin != NULL )
    delete begin;
  begin = end->clone();

  if ( end != NULL )
  {
    delete end;
    end = NULL;
  }

  for ( TObjectOrder i = 0; i < childIntervals.size(); ++i )
  {
    if ( childIntervals[ i ]->getEnd()->getTime() <= begin->getTime() )
      childIntervals[ i ]->calcNext( displayList );

    if ( ( end == NULL
           && childIntervals[ i ]->getEnd()->getTime() < childIntervals[ i ]->getWindow()->getTrace()->getEndTime() )
         ||
         ( end != NULL
           && childIntervals[ i ]->getEnd()->getTime() < end->getTime()
           && childIntervals[ i ]->getEnd()->getTime() < childIntervals[ i ]->getWindow()->getTrace()->getEndTime() )
        )
    {
      if ( end != NULL )
        delete end;
      end = childIntervals[ i ]->getEnd()->clone();
    }

    // Apply factor
    double tmpAbsFactor = fabs( window->getFactor( i ) );
    if ( tmpAbsFactor < 1.0 )
    {
      if ( window->getFactor( i ) < 0.0 )
        info.values.push_back( -childIntervals[ i ]->getValue() / ( 1.0 / tmpAbsFactor ) );
      else
        info.values.push_back( childIntervals[ i ]->getValue() / ( 1.0 / tmpAbsFactor ) );
    }
    else
      info.values.push_back( childIntervals[ i ]->getValue() * window->getFactor( i ) );
  }
  if( end == NULL )
    end = ( (KTrace *)window->getTrace() )->end();

  info.dataBeginTime = childIntervals[ 0 ]->getBegin()->getTime();
  currentValue = function->execute( &info );

  return displayList;
}

KRecordList *IntervalDerived::calcPrev( KRecordList *displayList, bool initCalc )
{
  info.values.clear();

  if ( displayList == NULL )
    displayList = &myDisplayList;

  if ( end != NULL )
    delete end;
  end = begin->clone();

  if ( begin != NULL )
  {
    delete begin;
    begin = NULL;
  }

  for ( TObjectOrder i = 0; i < childIntervals.size(); i++ )
  {
    if ( childIntervals[ i ]->getBegin()->getTime() >= end->getTime() )
      childIntervals[ i ]->calcPrev( displayList );

    if ( begin == NULL ||
         childIntervals[ i ]->getBegin()->getTime() > begin->getTime() )
    {
      if ( begin != NULL )
        delete begin;
      begin = childIntervals[ i ]->getBegin()->clone();
    }

    // Apply factor
    double tmpAbsFactor = fabs( window->getFactor( i ) );
    if ( tmpAbsFactor < 1.0 )
    {
      if ( window->getFactor( i ) < 0.0 )
        info.values.push_back( -childIntervals[ i ]->getValue() / ( 1.0 / tmpAbsFactor ) );
      else
        info.values.push_back( childIntervals[ i ]->getValue() / ( 1.0 / tmpAbsFactor ) );
    }
    else
      info.values.push_back( childIntervals[ i ]->getValue() * window->getFactor( i ) );
  }

  info.dataBeginTime = childIntervals[ 0 ]->getBegin()->getTime();
  currentValue = function->execute( &info );

  return displayList;
}

TWindowLevel IntervalDerived::getWindowLevel() const
{
  return window->getLevel();
}

Interval *IntervalDerived::getWindowInterval( TWindowLevel whichLevel,
    TObjectOrder whichOrder )
{
  return window->getLevelInterval( whichLevel, whichOrder );
}

bool IntervalDerived::IsDerivedWindow() const
{
  return window->isDerivedWindow();
}

TWindowLevel IntervalDerived::getComposeLevel( TWindowLevel whichLevel ) const
{
  return window->getComposeLevel( whichLevel );
}

KTrace *IntervalDerived::getWindowTrace() const
{
  return (KTrace*)window->getTrace();
}

void IntervalDerived::setChilds()
{
  KWindow *window1;
  KWindow *window2;
  TApplOrder tmpAppl;
  TTaskOrder tmpTask;
  TThreadOrder tmpThread;
  TNodeOrder tmpNode;
  TCPUOrder tmpCPU;

  childIntervals.clear();

  if ( window->getParent( 0 )->getLevel() >= window->getParent( 1 )->getLevel() )
  {
    window1 = (KWindow *) window->getParent( 0 );
    window2 = (KWindow *) window->getParent( 1 );
  }
  else
  {
    window1 = (KWindow *) window->getParent( 1 );
    window2 = (KWindow *) window->getParent( 0 );
  }

  if ( window1->getLevel() == APPLICATION )
  {
    tmpAppl = order;
  }
  else if ( window1->getLevel() == TASK )
  {
    window1->getTrace()->getTaskLocation( order, tmpAppl, tmpTask );
  }
  else if ( window1->getLevel() == THREAD )
  {
    window1->getTrace()->getThreadLocation( order, tmpAppl, tmpTask, tmpThread );
  }
  else if ( window1->getLevel() == NODE )
  {
    tmpNode = order;
  }
  else if ( window1->getLevel() == CPU )
  {
    window1->getTrace()->getCPULocation( order, tmpNode, tmpCPU );
  }

  childIntervals.push_back( window1->getLevelInterval( TOPCOMPOSE1, order, true ) );

  if ( window2->getLevel() == WORKLOAD )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, 0, true ) );
  }
  else if ( window2->getLevel() == APPLICATION )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, tmpAppl, true ) );
  }
  else if ( window2->getLevel() == TASK )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1,
                              window2->getTrace()->getGlobalTask( tmpAppl, tmpTask ), true ) );
  }
  else if ( window2->getLevel() == THREAD )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1,
                              window2->getTrace()->getGlobalThread( tmpAppl, tmpTask, tmpThread ), true ) );
  }
  else if ( window2->getLevel() == SYSTEM )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, 0, true ) );
  }
  else if ( window2->getLevel() == NODE )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1, tmpNode, true ) );
  }
  else if ( window2->getLevel() == CPU )
  {
    childIntervals.push_back( window2->getLevelInterval( TOPCOMPOSE1,
                              window2->getTrace()->getGlobalCPU( tmpNode, tmpCPU ), true ) );
  }
}
<|endoftext|>


<commit_before>/*
 * An istream handler which sends data to a socket.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "sink_fd.hxx"
#include "pool.hxx"
#include "direct.hxx"
#include "system/fd-util.h"
#include "event/Event.hxx"
#include "event/Callback.hxx"
#include "istream_pointer.hxx"

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>

struct SinkFd {
    struct pool *pool;

    IstreamPointer input;

    int fd;
    FdType fd_type;
    const SinkFdHandler *handler;
    void *handler_ctx;

    Event event;

    /**
     * Set to true each time data was received from the istream.
     */
    bool got_data;

    /**
     * This flag is used to determine if the EV_WRITE event shall be
     * scheduled after a splice().  We need to add the event only if
     * the splice() was triggered by EV_WRITE, because then we're
     * responsible for querying more data.
     */
    bool got_event = false;

#ifndef NDEBUG
    bool valid = true;
#endif

    SinkFd(struct pool &_pool, Istream &_istream,
           int _fd, FdType _fd_type,
           const SinkFdHandler &_handler, void *_handler_ctx)
        :pool(&_pool),
         input(_istream, MakeIstreamHandler<SinkFd>::handler, this,
               istream_direct_mask_to(fd_type)),
         fd(_fd), fd_type(_fd_type),
         handler(&_handler), handler_ctx(_handler_ctx) {
        ScheduleWrite();
    }

    void ScheduleWrite() {
        assert(fd >= 0);
        assert(input.IsDefined());

        got_event = false;
        event.Add();
    }

    void EventCallback();

    /* request istream handler */
    size_t OnData(const void *data, size_t length);
    ssize_t OnDirect(FdType type, int fd, size_t max_length);
    void OnEof();
    void OnError(GError *error);
};

/*
 * istream handler
 *
 */

inline size_t
SinkFd::OnData(const void *data, size_t length)
{
    got_data = true;

    ssize_t nbytes = IsAnySocket(fd_type)
        ? send(fd, data, length, MSG_DONTWAIT|MSG_NOSIGNAL)
        : write(fd, data, length);
    if (nbytes >= 0) {
        ScheduleWrite();
        return nbytes;
    } else if (errno == EAGAIN) {
        ScheduleWrite();
        return 0;
    } else {
        event.Delete();
        if (handler->send_error(errno, handler_ctx))
            input.Close();
        return 0;
    }
}

inline ssize_t
SinkFd::OnDirect(FdType type, gcc_unused int _fd, size_t max_length)
{
    got_data = true;

    ssize_t nbytes = istream_direct_to(fd, type, fd, fd_type,
                                       max_length);
    if (unlikely(nbytes < 0 && errno == EAGAIN)) {
        if (!fd_ready_for_writing(fd)) {
            ScheduleWrite();
            return ISTREAM_RESULT_BLOCKING;
        }

        /* try again, just in case connection->fd has become ready
           between the first istream_direct_to_socket() call and
           fd_ready_for_writing() */
        nbytes = istream_direct_to(fd, type, fd, fd_type, max_length);
    }

    if (likely(nbytes > 0) && (got_event || type == FdType::FD_FILE))
        /* regular files don't have support for EV_READ, and thus the
           sink is responsible for triggering the next splice */
        ScheduleWrite();

    return nbytes;
}

inline void
SinkFd::OnEof()
{
    got_data = true;

#ifndef NDEBUG
    valid = false;
#endif

    event.Delete();

    handler->input_eof(handler_ctx);
}

inline void
SinkFd::OnError(GError *error)
{
    got_data = true;

#ifndef NDEBUG
    valid = false;
#endif

    event.Delete();

    handler->input_error(error, handler_ctx);
}

/*
 * libevent callback
 *
 */

inline void
SinkFd::EventCallback()
{
    pool_ref(pool);

    got_event = true;
    got_data = false;
    input.Read();

    if (!got_data)
        /* the fd is ready for writing, but the istream is blocking -
           don't try again for now */
        event.Delete();

    pool_unref(pool);
    pool_commit();
}

/*
 * constructor
 *
 */

SinkFd *
sink_fd_new(struct pool &pool, Istream &istream,
            int fd, FdType fd_type,
            const SinkFdHandler &handler, void *ctx)
{
    assert(fd >= 0);
    assert(handler.input_eof != nullptr);
    assert(handler.input_error != nullptr);
    assert(handler.send_error != nullptr);

    return NewFromPool<SinkFd>(pool, pool, istream, fd, fd_type,
                               handler, ctx);
}

void
sink_fd_read(SinkFd *ss)
{
    assert(ss != nullptr);
    assert(ss->valid);
    assert(ss->input.IsDefined());

    ss->input.Read();
}

void
sink_fd_close(SinkFd *ss)
{
    assert(ss != nullptr);
    assert(ss->valid);
    assert(ss->input.IsDefined());

#ifndef NDEBUG
    ss->valid = false;
#endif

    ss->event.Delete();
    ss->input.Close();
}
<commit_msg>istream/sink_fd: fix typo in constructor<commit_after>/*
 * An istream handler which sends data to a socket.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "sink_fd.hxx"
#include "pool.hxx"
#include "direct.hxx"
#include "system/fd-util.h"
#include "event/Event.hxx"
#include "event/Callback.hxx"
#include "istream_pointer.hxx"

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>

struct SinkFd {
    struct pool *pool;

    IstreamPointer input;

    int fd;
    FdType fd_type;
    const SinkFdHandler *handler;
    void *handler_ctx;

    Event event;

    /**
     * Set to true each time data was received from the istream.
     */
    bool got_data;

    /**
     * This flag is used to determine if the EV_WRITE event shall be
     * scheduled after a splice().  We need to add the event only if
     * the splice() was triggered by EV_WRITE, because then we're
     * responsible for querying more data.
     */
    bool got_event = false;

#ifndef NDEBUG
    bool valid = true;
#endif

    SinkFd(struct pool &_pool, Istream &_istream,
           int _fd, FdType _fd_type,
           const SinkFdHandler &_handler, void *_handler_ctx)
        :pool(&_pool),
         input(_istream, MakeIstreamHandler<SinkFd>::handler, this,
               istream_direct_mask_to(_fd_type)),
         fd(_fd), fd_type(_fd_type),
         handler(&_handler), handler_ctx(_handler_ctx) {
        ScheduleWrite();
    }

    void ScheduleWrite() {
        assert(fd >= 0);
        assert(input.IsDefined());

        got_event = false;
        event.Add();
    }

    void EventCallback();

    /* request istream handler */
    size_t OnData(const void *data, size_t length);
    ssize_t OnDirect(FdType type, int fd, size_t max_length);
    void OnEof();
    void OnError(GError *error);
};

/*
 * istream handler
 *
 */

inline size_t
SinkFd::OnData(const void *data, size_t length)
{
    got_data = true;

    ssize_t nbytes = IsAnySocket(fd_type)
        ? send(fd, data, length, MSG_DONTWAIT|MSG_NOSIGNAL)
        : write(fd, data, length);
    if (nbytes >= 0) {
        ScheduleWrite();
        return nbytes;
    } else if (errno == EAGAIN) {
        ScheduleWrite();
        return 0;
    } else {
        event.Delete();
        if (handler->send_error(errno, handler_ctx))
            input.Close();
        return 0;
    }
}

inline ssize_t
SinkFd::OnDirect(FdType type, gcc_unused int _fd, size_t max_length)
{
    got_data = true;

    ssize_t nbytes = istream_direct_to(fd, type, fd, fd_type,
                                       max_length);
    if (unlikely(nbytes < 0 && errno == EAGAIN)) {
        if (!fd_ready_for_writing(fd)) {
            ScheduleWrite();
            return ISTREAM_RESULT_BLOCKING;
        }

        /* try again, just in case connection->fd has become ready
           between the first istream_direct_to_socket() call and
           fd_ready_for_writing() */
        nbytes = istream_direct_to(fd, type, fd, fd_type, max_length);
    }

    if (likely(nbytes > 0) && (got_event || type == FdType::FD_FILE))
        /* regular files don't have support for EV_READ, and thus the
           sink is responsible for triggering the next splice */
        ScheduleWrite();

    return nbytes;
}

inline void
SinkFd::OnEof()
{
    got_data = true;

#ifndef NDEBUG
    valid = false;
#endif

    event.Delete();

    handler->input_eof(handler_ctx);
}

inline void
SinkFd::OnError(GError *error)
{
    got_data = true;

#ifndef NDEBUG
    valid = false;
#endif

    event.Delete();

    handler->input_error(error, handler_ctx);
}

/*
 * libevent callback
 *
 */

inline void
SinkFd::EventCallback()
{
    pool_ref(pool);

    got_event = true;
    got_data = false;
    input.Read();

    if (!got_data)
        /* the fd is ready for writing, but the istream is blocking -
           don't try again for now */
        event.Delete();

    pool_unref(pool);
    pool_commit();
}

/*
 * constructor
 *
 */

SinkFd *
sink_fd_new(struct pool &pool, Istream &istream,
            int fd, FdType fd_type,
            const SinkFdHandler &handler, void *ctx)
{
    assert(fd >= 0);
    assert(handler.input_eof != nullptr);
    assert(handler.input_error != nullptr);
    assert(handler.send_error != nullptr);

    return NewFromPool<SinkFd>(pool, pool, istream, fd, fd_type,
                               handler, ctx);
}

void
sink_fd_read(SinkFd *ss)
{
    assert(ss != nullptr);
    assert(ss->valid);
    assert(ss->input.IsDefined());

    ss->input.Read();
}

void
sink_fd_close(SinkFd *ss)
{
    assert(ss != nullptr);
    assert(ss->valid);
    assert(ss->input.IsDefined());

#ifndef NDEBUG
    ss->valid = false;
#endif

    ss->event.Delete();
    ss->input.Close();
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.

#include "test/test_pivx.h"
#include "primitives/transaction.h"
#include "evo/providertx.h"
#include "evo/specialtx.h"
#include "messagesigner.h"
#include "netbase.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(evo_specialtx_tests, TestingSetup)

static CKey GetRandomKey()
{
    CKey key;
    key.MakeNewKey(true);
    return key;
}

static CKeyID GetRandomKeyID()
{
    return GetRandomKey().GetPubKey().GetID();
}

static CScript GetRandomScript()
{
    return GetScriptForDestination(GetRandomKeyID());
}

static ProRegPL GetRandomProRegPayload()
{
    ProRegPL pl;
    pl.collateralOutpoint.hash = GetRandHash();
    pl.collateralOutpoint.n = InsecureRandBits(2);
    BOOST_CHECK(Lookup("57.12.210.11:51472", pl.addr, Params().GetDefaultPort(), false));
    pl.keyIDOwner = GetRandomKeyID();
    pl.keyIDOperator = GetRandomKeyID();
    pl.keyIDVoting = GetRandomKeyID();
    pl.scriptPayout = GetRandomScript();
    pl.nOperatorReward = InsecureRandRange(10000);
    pl.scriptOperatorPayout = GetRandomScript();
    pl.inputsHash = GetRandHash();
    pl.vchSig = InsecureRandBytes(63);
    return pl;
}

BOOST_AUTO_TEST_CASE(special_tx_validation_test)
{
    CMutableTransaction mtx;
    CValidationState state;

    // v1 can only be Type=0
    mtx.nType = CTransaction::TxType::PROREG;
    mtx.nVersion = CTransaction::TxVersion::LEGACY;
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-version");

    // version >= Sapling, type = 0, payload != null.
    mtx.nType = CTransaction::TxType::NORMAL;
    mtx.extraPayload = std::vector<uint8_t>(10, 1);
    mtx.nVersion = CTransaction::TxVersion::SAPLING;
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-payload");

    // version >= Sapling, type = 0, payload == null --> pass
    mtx.extraPayload = nullopt;
    BOOST_CHECK(CheckSpecialTxNoContext(CTransaction(mtx), state));

    // nVersion>=2 and nType!=0 without extrapayload
    mtx.nType = CTransaction::TxType::PROREG;
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK(state.GetRejectReason().find("without extra payload"));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-empty");

    // Size limits
    mtx.extraPayload = std::vector<uint8_t>(MAX_SPECIALTX_EXTRAPAYLOAD + 1, 1);
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-oversize");

    // Remove one element, so now it passes the size check
    mtx.extraPayload->pop_back();
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-payload");

    // valid payload but invalid inputs hash
    mtx.extraPayload->clear();
    ProRegPL pl = GetRandomProRegPayload();
    SetTxPayload(mtx, pl);
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-inputs-hash");

    // all good.
    mtx.vin.emplace_back(GetRandHash(), 0);
    mtx.extraPayload->clear();
    pl.inputsHash = CalcTxInputsHash(CTransaction(mtx));
    SetTxPayload(mtx, pl);
    BOOST_CHECK(CheckSpecialTxNoContext(CTransaction(mtx), state));
}

BOOST_AUTO_TEST_CASE(providertx_setpayload_test)
{
    const ProRegPL& pl = GetRandomProRegPayload();

    CMutableTransaction mtx;
    SetTxPayload(mtx, pl);
    ProRegPL pl2;
    BOOST_CHECK(GetTxPayload(mtx, pl2));
    BOOST_CHECK(pl.collateralOutpoint == pl2.collateralOutpoint);
    BOOST_CHECK(pl.addr  == pl2.addr);
    BOOST_CHECK(pl.keyIDOwner == pl2.keyIDOwner);
    BOOST_CHECK(pl.keyIDOperator == pl2.keyIDOperator);
    BOOST_CHECK(pl.keyIDVoting == pl2.keyIDVoting);
    BOOST_CHECK(pl.scriptPayout == pl2.scriptPayout);
    BOOST_CHECK(pl.nOperatorReward  == pl2.nOperatorReward);
    BOOST_CHECK(pl.scriptOperatorPayout == pl2.scriptOperatorPayout);
    BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
    BOOST_CHECK(pl.vchSig == pl2.vchSig);
}

BOOST_AUTO_TEST_CASE(providertx_checkstringsig_test)
{
    ProRegPL pl = GetRandomProRegPayload();
    pl.vchSig.clear();
    const CKey& key = GetRandomKey();
    BOOST_CHECK(CMessageSigner::SignMessage(pl.MakeSignString(), pl.vchSig, key));

    std::string strError;
    const CKeyID& keyID = key.GetPubKey().GetID();
    BOOST_CHECK(CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
    // Change owner address or script payout
    pl.keyIDOwner = GetRandomKeyID();
    BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
    pl.scriptPayout = GetRandomScript();
    BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>[Tests] Add Get/Set payload unit-test for ProUpServ txes<commit_after>// Copyright (c) 2021 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.

#include "test/test_pivx.h"
#include "primitives/transaction.h"
#include "evo/providertx.h"
#include "evo/specialtx.h"
#include "messagesigner.h"
#include "netbase.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(evo_specialtx_tests, TestingSetup)

static CKey GetRandomKey()
{
    CKey key;
    key.MakeNewKey(true);
    return key;
}

static CKeyID GetRandomKeyID()
{
    return GetRandomKey().GetPubKey().GetID();
}

static CScript GetRandomScript()
{
    return GetScriptForDestination(GetRandomKeyID());
}

static ProRegPL GetRandomProRegPayload()
{
    ProRegPL pl;
    pl.collateralOutpoint.hash = GetRandHash();
    pl.collateralOutpoint.n = InsecureRandBits(2);
    BOOST_CHECK(Lookup("57.12.210.11:51472", pl.addr, Params().GetDefaultPort(), false));
    pl.keyIDOwner = GetRandomKeyID();
    pl.keyIDOperator = GetRandomKeyID();
    pl.keyIDVoting = GetRandomKeyID();
    pl.scriptPayout = GetRandomScript();
    pl.nOperatorReward = InsecureRandRange(10000);
    pl.scriptOperatorPayout = GetRandomScript();
    pl.inputsHash = GetRandHash();
    pl.vchSig = InsecureRandBytes(63);
    return pl;
}

static ProUpServPL GetRandomProUpServPayload()
{
    ProUpServPL pl;
    pl.proTxHash = GetRandHash();
    BOOST_CHECK(Lookup("127.0.0.1:51472", pl.addr, Params().GetDefaultPort(), false));
    pl.scriptOperatorPayout = GetRandomScript();
    pl.inputsHash = GetRandHash();
    pl.vchSig = InsecureRandBytes(63);
    return pl;
}

BOOST_AUTO_TEST_CASE(protx_validation_test)
{
    CMutableTransaction mtx;
    CValidationState state;

    // v1 can only be Type=0
    mtx.nType = CTransaction::TxType::PROREG;
    mtx.nVersion = CTransaction::TxVersion::LEGACY;
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-version");

    // version >= Sapling, type = 0, payload != null.
    mtx.nType = CTransaction::TxType::NORMAL;
    mtx.extraPayload = std::vector<uint8_t>(10, 1);
    mtx.nVersion = CTransaction::TxVersion::SAPLING;
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-payload");

    // version >= Sapling, type = 0, payload == null --> pass
    mtx.extraPayload = nullopt;
    BOOST_CHECK(CheckSpecialTxNoContext(CTransaction(mtx), state));

    // nVersion>=2 and nType!=0 without extrapayload
    mtx.nType = CTransaction::TxType::PROREG;
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK(state.GetRejectReason().find("without extra payload"));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-empty");

    // Size limits
    mtx.extraPayload = std::vector<uint8_t>(MAX_SPECIALTX_EXTRAPAYLOAD + 1, 1);
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-oversize");

    // Remove one element, so now it passes the size check
    mtx.extraPayload->pop_back();
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-payload");

    // valid payload but invalid inputs hash
    mtx.extraPayload->clear();
    ProRegPL pl = GetRandomProRegPayload();
    SetTxPayload(mtx, pl);
    BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
    BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-inputs-hash");

    // all good.
    mtx.vin.emplace_back(GetRandHash(), 0);
    mtx.extraPayload->clear();
    pl.inputsHash = CalcTxInputsHash(CTransaction(mtx));
    SetTxPayload(mtx, pl);
    BOOST_CHECK(CheckSpecialTxNoContext(CTransaction(mtx), state));
}

BOOST_AUTO_TEST_CASE(proreg_setpayload_test)
{
    const ProRegPL& pl = GetRandomProRegPayload();

    CMutableTransaction mtx;
    SetTxPayload(mtx, pl);
    ProRegPL pl2;
    BOOST_CHECK(GetTxPayload(mtx, pl2));
    BOOST_CHECK(pl.collateralOutpoint == pl2.collateralOutpoint);
    BOOST_CHECK(pl.addr  == pl2.addr);
    BOOST_CHECK(pl.keyIDOwner == pl2.keyIDOwner);
    BOOST_CHECK(pl.keyIDOperator == pl2.keyIDOperator);
    BOOST_CHECK(pl.keyIDVoting == pl2.keyIDVoting);
    BOOST_CHECK(pl.scriptPayout == pl2.scriptPayout);
    BOOST_CHECK(pl.nOperatorReward  == pl2.nOperatorReward);
    BOOST_CHECK(pl.scriptOperatorPayout == pl2.scriptOperatorPayout);
    BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
    BOOST_CHECK(pl.vchSig == pl2.vchSig);
}

BOOST_AUTO_TEST_CASE(proupserv_setpayload_test)
{
    const ProUpServPL& pl = GetRandomProUpServPayload();

    CMutableTransaction mtx;
    SetTxPayload(mtx, pl);
    ProUpServPL pl2;
    BOOST_CHECK(GetTxPayload(mtx, pl2));
    BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
    BOOST_CHECK(pl.addr  == pl2.addr);
    BOOST_CHECK(pl.scriptOperatorPayout == pl2.scriptOperatorPayout);
    BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
    BOOST_CHECK(pl.vchSig == pl2.vchSig);
}

BOOST_AUTO_TEST_CASE(proreg_checkstringsig_test)
{
    ProRegPL pl = GetRandomProRegPayload();
    pl.vchSig.clear();
    const CKey& key = GetRandomKey();
    BOOST_CHECK(CMessageSigner::SignMessage(pl.MakeSignString(), pl.vchSig, key));

    std::string strError;
    const CKeyID& keyID = key.GetPubKey().GetID();
    BOOST_CHECK(CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
    // Change owner address or script payout
    pl.keyIDOwner = GetRandomKeyID();
    BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
    pl.scriptPayout = GetRandomScript();
    BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>