<commit_before>#include "QWsServer.h"

#include <QStringList>
#include <QByteArray>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDebug>

QWsServer::QWsServer(QObject * parent)
	: QObject(parent)
{
	tcpServer = new QTcpServer(this);
	connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newTcpConnection()));
	qsrand( QDateTime::currentMSecsSinceEpoch() );
}

QWsServer::~QWsServer()
{
	tcpServer->deleteLater();
}

bool QWsServer::listen(const QHostAddress & address, quint16 port)
{
	return tcpServer->listen(address, port);
}

void QWsServer::close()
{
	tcpServer->close();
}

QAbstractSocket::SocketError QWsServer::serverError()
{
	return tcpServer->serverError();
}

QString QWsServer::errorString()
{
	return tcpServer->errorString();
}

void QWsServer::newTcpConnection()
{
	QTcpSocket * clientSocket = tcpServer->nextPendingConnection();
	QObject * clientObject = qobject_cast<QObject*>(clientSocket);
	connect(clientObject, SIGNAL(readyRead()), this, SLOT(dataReceived()));
}

void QWsServer::dataReceived()
{
	QTcpSocket * clientSocket = qobject_cast<QTcpSocket*>(sender());
	if (clientSocket == 0)
		return;

	while (true)
	{
		QStringList lines = QString(clientSocket->readAll()).split("\r\n");
		if ( lines.length() < 3 )
			break;

		QString requestLine = lines[0];
		QStringList elements = requestLine.split(' ');
		if ( elements.length() != 3 || elements[0] != "GET" || elements[2] != "HTTP/1.1" )
			break;

		// Extract datas

		QString resourceName = elements[1];
		if ( !resourceName.startsWith('/') )
			break;

		bool content = false;
		int version = 0,
		    hostPort = 0;
		QString hostAddress,
			key, key1, key2, key3,
			origin,
			protocol;

		int i;
		for ( i = 1; i < lines.length(); i++ )
		{
			QString line = lines[i];
			if ( content )
			{
				key3 = line;
				i++;
				break;
			}
			else
			{
				if ( line.isEmpty() )
				{
					content = true;
					continue;
				}

				QString fieldName = line.section(':', 0, 0);
				QString fieldValue = line.section(':', 1).trimmed();
				if ( fieldName.isEmpty() || fieldValue.isEmpty() )
					break;

				if ( fieldName == "Sec-WebSocket-Version" )
					version = fieldValue.toInt();
				else if ( fieldName == "Host" )
				{
					hostAddress = fieldValue.section(':', 0, 0);
					hostPort = fieldValue.section(':', 1).toInt();
				}
				else if ( fieldName == "Sec-WebSocket-Key" )
					key = fieldValue;
				else if ( fieldName == "Sec-WebSocket-Key1" )
					key1 = fieldValue;
				else if ( fieldName == "Sec-WebSocket-Key2" )
					key2 = fieldValue;
				else if ( fieldName == "Origin" || fieldName == "Sec-WebSocket-Origin" )
					origin = fieldValue;
				else if ( fieldName == "Sec-WebSocket-Protocol" )
					protocol = fieldValue;
			}
		}
		if ( i != lines.length() )
			break;

		////////////////////////////////////////////////////////////////////

		//if ( version < 6 )
		//{
		//	qDebug() << "======== Handshake Received \n"
		//			 << request
		//			 << "======== \n";
		//}

		// If the mandatory params are not setted, we abort the connection to the Websocket server
		if ( hostAddress.isEmpty()
			|| resourceName.isEmpty()
			|| ( version >= 6 && key.length() != 24 )
			|| ( version < 6 && ( key1.isEmpty() || key2.isEmpty() || key3.length() != 8 ) )
           )
			break;

		////////////////////////////////////////////////////////////////////

		// Compose handshake answer

		QString answer;

		QString accept;
		if ( version >= 6 )
		{
			accept = computeAcceptV2( key );
			answer.append("HTTP/1.1 101 Switching Protocols\r\n");
			answer.append("Upgrade: websocket\r\n");
			answer.append("Connection: Upgrade\r\n");
			answer.append("Sec-WebSocket-Accept: " + accept + "\r\n" + "\r\n");
		}
		else
        {
            accept = computeAcceptV1( key1, key2, key3 );
			answer.append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");
			answer.append("Upgrade: WebSocket\r\n");
			answer.append("Connection: Upgrade\r\n");
			answer.append("Sec-WebSocket-Origin: " + origin + "\r\n");
			answer.append("Sec-WebSocket-Location: ws://" + hostAddress + ( hostPort ? (":"+QString::number(hostPort)) : "" ) + resourceName + "\r\n");
			if ( !protocol.isEmpty() )
				answer.append("Sec-WebSocket-Protocol: " + protocol + "\r\n");
			answer.append("\r\n");
			answer.append( accept );
		}

		//if ( version < 6 )
		//{
		//	qDebug() << "======== Handshake sent \n"
		//			 << answer
		//			 << "======== \n";
		//}

		// Handshake OK, new connection
		disconnect(clientSocket, SIGNAL(readyRead()), this, SLOT(dataReceived()));

		// Send handshake answer
		clientSocket->write( answer.toAscii() );
		clientSocket->flush();

		// TEMPORARY CODE FOR LINUX COMPATIBILITY
		QWsSocket * wsSocket = new QWsSocket( clientSocket, version, this );
		addPendingConnection( wsSocket );
		emit newConnection();

		/*
		// ORIGINAL CODE
		int socketDescriptor = clientSocket->socketDescriptor();
		incomingConnection( socketDescriptor );
		*/
		return;
	}

	clientSocket->deleteLater();
}

void QWsServer::incomingConnection( int socketDescriptor )
{
	QTcpSocket * tcpSocket = new QTcpSocket(tcpServer);
	tcpSocket->setSocketDescriptor( socketDescriptor, QAbstractSocket::ConnectedState );
	QWsSocket * wsSocket = new QWsSocket( tcpSocket, 6, this );

	addPendingConnection( wsSocket );
	emit newConnection();
}

void QWsServer::addPendingConnection( QWsSocket * socket )
{
	if ( pendingConnections.size() < maxPendingConnections() )
		pendingConnections.enqueue(socket);
}

QWsSocket * QWsServer::nextPendingConnection()
{
	return pendingConnections.dequeue();
}

bool QWsServer::hasPendingConnections()
{
	if ( pendingConnections.size() > 0 )
		return true;
	return false;
}

int QWsServer::maxPendingConnections()
{
	return tcpServer->maxPendingConnections();
}

bool QWsServer::isListening()
{
	return tcpServer->isListening();
}

QNetworkProxy QWsServer::proxy()
{
	return tcpServer->proxy();
}

QHostAddress QWsServer::serverAddress()
{
	return tcpServer->serverAddress();
}

quint16 QWsServer::serverPort()
{
	return tcpServer->serverPort();
}

void QWsServer::setMaxPendingConnections( int numConnections )
{
	tcpServer->setMaxPendingConnections( numConnections );
}

void QWsServer::setProxy( const QNetworkProxy & networkProxy )
{
	tcpServer->setProxy( networkProxy );
}

bool QWsServer::setSocketDescriptor( int socketDescriptor )
{
	return tcpServer->setSocketDescriptor( socketDescriptor );
}

int QWsServer::socketDescriptor()
{
	return tcpServer->socketDescriptor();
}

bool QWsServer::waitForNewConnection( int msec, bool * timedOut )
{
	return tcpServer->waitForNewConnection( msec, timedOut );
}

QString QWsServer::computeAcceptV2(QString key)
{
	key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
	QByteArray hash = QCryptographicHash::hash ( key.toUtf8(), QCryptographicHash::Sha1 );
	return hash.toBase64();
}

QString QWsServer::computeAcceptV1( QString key1, QString key2, QString key3 )
{
	QString numStr1;
	QString numStr2;
	int numSpaces1 = 0;
	int numSpaces2 = 0;

	QChar carac;
	for ( int i=0 ; i<key1.size() ; i++ )
	{
		carac = key1[ i ];
		if ( carac.isDigit() )
			numStr1.append( carac );
		else if ( carac == ' ' )
			numSpaces1++;
	}
	for ( int i=0 ; i<key2.size() ; i++ )
	{
		carac = key2[ i ];
		if ( carac.isDigit() )
			numStr2.append( carac );
		else if ( carac == ' ' )
			numSpaces2++;
	}

	quint32 num1 = numStr1.toUInt();
	quint32 num2 = numStr2.toUInt();

	//qDebug() << QString::number(num1);
	//qDebug() << QString::number(num2);

	//qDebug() << QString::number(numSpaces1);
	//qDebug() << QString::number(numSpaces2);

	num1 /= numSpaces1;
	num2 /= numSpaces2;

	QString concat = serializeInt( num1 ) + serializeInt( num2 ) + key3;

	QByteArray md5 = QCryptographicHash::hash( concat.toAscii(), QCryptographicHash::Md5 );

	return QString( md5 );
}

QString QWsServer::serializeInt( quint32 number, quint8 nbBytes )
{
	QString bin;
	quint8 currentNbBytes = 0;
	while (number > 0 && currentNbBytes < nbBytes)
	{
		bin.prepend( QChar::fromAscii(number) );
		number = number >> 8;
		currentNbBytes++;
	}
	while (currentNbBytes < nbBytes)
	{
		bin.prepend( QChar::fromAscii(0) );
		currentNbBytes++;
	}
	return bin;
}
<commit_msg>Compile fix for QWsSocket.cpp<commit_after>#include "QWsServer.h"

#include <QStringList>
#include <QByteArray>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDebug>

QWsServer::QWsServer(QObject * parent)
	: QObject(parent)
{
	tcpServer = new QTcpServer(this);
	connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newTcpConnection()));
	qsrand( QDateTime::currentMSecsSinceEpoch() );
}

QWsServer::~QWsServer()
{
	tcpServer->deleteLater();
}

bool QWsServer::listen(const QHostAddress & address, quint16 port)
{
	return tcpServer->listen(address, port);
}

void QWsServer::close()
{
	tcpServer->close();
}

QAbstractSocket::SocketError QWsServer::serverError()
{
	return tcpServer->serverError();
}

QString QWsServer::errorString()
{
	return tcpServer->errorString();
}

void QWsServer::newTcpConnection()
{
	QTcpSocket * clientSocket = tcpServer->nextPendingConnection();
	QObject * clientObject = qobject_cast<QObject*>(clientSocket);
	connect(clientObject, SIGNAL(readyRead()), this, SLOT(dataReceived()));
}

void QWsServer::dataReceived()
{
	QTcpSocket * clientSocket = qobject_cast<QTcpSocket*>(sender());
	if (clientSocket == 0)
		return;

	while (true)
	{
		QStringList lines = QString(clientSocket->readAll()).split("\r\n");
		if ( lines.length() < 3 )
			break;

		QString requestLine = lines[0];
		QStringList elements = requestLine.split(' ');
		if ( elements.length() != 3 || elements[0] != "GET" || elements[2] != "HTTP/1.1" )
			break;

		// Extract datas

		QString resourceName = elements[1];
		if ( !resourceName.startsWith('/') )
			break;

		bool content = false;
		int version = 0,
		    hostPort = 0;
		QString hostAddress,
			key, key1, key2, key3,
			origin,
			protocol;

		int i;
		for ( i = 1; i < lines.length(); i++ )
		{
			QString line = lines[i];
			if ( content )
			{
				key3 = line;
				i++;
				break;
			}
			else
			{
				if ( line.isEmpty() )
				{
					content = true;
					continue;
				}

				QString fieldName = line.section(':', 0, 0);
				QString fieldValue = line.section(':', 1).trimmed();
				if ( fieldName.isEmpty() || fieldValue.isEmpty() )
					break;

				if ( fieldName == "Sec-WebSocket-Version" )
					version = fieldValue.toInt();
				else if ( fieldName == "Host" )
				{
					hostAddress = fieldValue.section(':', 0, 0);
					hostPort = fieldValue.section(':', 1).toInt();
				}
				else if ( fieldName == "Sec-WebSocket-Key" )
					key = fieldValue;
				else if ( fieldName == "Sec-WebSocket-Key1" )
					key1 = fieldValue;
				else if ( fieldName == "Sec-WebSocket-Key2" )
					key2 = fieldValue;
				else if ( fieldName == "Origin" || fieldName == "Sec-WebSocket-Origin" )
					origin = fieldValue;
				else if ( fieldName == "Sec-WebSocket-Protocol" )
					protocol = fieldValue;
			}
		}
		if ( i != lines.length() )
			break;

		////////////////////////////////////////////////////////////////////

		//if ( version < 6 )
		//{
		//	qDebug() << "======== Handshake Received \n"
		//			 << request
		//			 << "======== \n";
		//}

		// If the mandatory params are not setted, we abort the connection to the Websocket server
		if ( hostAddress.isEmpty()
			|| resourceName.isEmpty()
			|| ( version >= 6 && key.length() != 24 )
			|| ( version < 6 && ( key1.isEmpty() || key2.isEmpty() || key3.length() != 8 ) )
           )
			break;

		////////////////////////////////////////////////////////////////////

		// Compose handshake answer

		QString answer;

		QString accept;
		if ( version >= 6 )
		{
			accept = computeAcceptV2( key );
			answer.append("HTTP/1.1 101 Switching Protocols\r\n");
			answer.append("Upgrade: websocket\r\n");
			answer.append("Connection: Upgrade\r\n");
			answer.append("Sec-WebSocket-Accept: " + accept + "\r\n" + "\r\n");
		}
		else
        {
            accept = computeAcceptV1( key1, key2, key3 );
			answer.append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");
			answer.append("Upgrade: WebSocket\r\n");
			answer.append("Connection: Upgrade\r\n");
			answer.append("Sec-WebSocket-Origin: " + origin + "\r\n");
            answer.append("Sec-WebSocket-Location: ws://" + hostAddress +
                          ( hostPort ? QString(":%1").arg(hostPort) : QString() ) + resourceName +
                          "\r\n");
			if ( !protocol.isEmpty() )
				answer.append("Sec-WebSocket-Protocol: " + protocol + "\r\n");
			answer.append("\r\n");
			answer.append( accept );
		}

		//if ( version < 6 )
		//{
		//	qDebug() << "======== Handshake sent \n"
		//			 << answer
		//			 << "======== \n";
		//}

		// Handshake OK, new connection
		disconnect(clientSocket, SIGNAL(readyRead()), this, SLOT(dataReceived()));

		// Send handshake answer
		clientSocket->write( answer.toAscii() );
		clientSocket->flush();

		// TEMPORARY CODE FOR LINUX COMPATIBILITY
		QWsSocket * wsSocket = new QWsSocket( clientSocket, version, this );
		addPendingConnection( wsSocket );
		emit newConnection();

		/*
		// ORIGINAL CODE
		int socketDescriptor = clientSocket->socketDescriptor();
		incomingConnection( socketDescriptor );
		*/
		return;
	}

	clientSocket->deleteLater();
}

void QWsServer::incomingConnection( int socketDescriptor )
{
	QTcpSocket * tcpSocket = new QTcpSocket(tcpServer);
	tcpSocket->setSocketDescriptor( socketDescriptor, QAbstractSocket::ConnectedState );
	QWsSocket * wsSocket = new QWsSocket( tcpSocket, 6, this );

	addPendingConnection( wsSocket );
	emit newConnection();
}

void QWsServer::addPendingConnection( QWsSocket * socket )
{
	if ( pendingConnections.size() < maxPendingConnections() )
		pendingConnections.enqueue(socket);
}

QWsSocket * QWsServer::nextPendingConnection()
{
	return pendingConnections.dequeue();
}

bool QWsServer::hasPendingConnections()
{
	if ( pendingConnections.size() > 0 )
		return true;
	return false;
}

int QWsServer::maxPendingConnections()
{
	return tcpServer->maxPendingConnections();
}

bool QWsServer::isListening()
{
	return tcpServer->isListening();
}

QNetworkProxy QWsServer::proxy()
{
	return tcpServer->proxy();
}

QHostAddress QWsServer::serverAddress()
{
	return tcpServer->serverAddress();
}

quint16 QWsServer::serverPort()
{
	return tcpServer->serverPort();
}

void QWsServer::setMaxPendingConnections( int numConnections )
{
	tcpServer->setMaxPendingConnections( numConnections );
}

void QWsServer::setProxy( const QNetworkProxy & networkProxy )
{
	tcpServer->setProxy( networkProxy );
}

bool QWsServer::setSocketDescriptor( int socketDescriptor )
{
	return tcpServer->setSocketDescriptor( socketDescriptor );
}

int QWsServer::socketDescriptor()
{
	return tcpServer->socketDescriptor();
}

bool QWsServer::waitForNewConnection( int msec, bool * timedOut )
{
	return tcpServer->waitForNewConnection( msec, timedOut );
}

QString QWsServer::computeAcceptV2(QString key)
{
	key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
	QByteArray hash = QCryptographicHash::hash ( key.toUtf8(), QCryptographicHash::Sha1 );
	return hash.toBase64();
}

QString QWsServer::computeAcceptV1( QString key1, QString key2, QString key3 )
{
	QString numStr1;
	QString numStr2;
	int numSpaces1 = 0;
	int numSpaces2 = 0;

	QChar carac;
	for ( int i=0 ; i<key1.size() ; i++ )
	{
		carac = key1[ i ];
		if ( carac.isDigit() )
			numStr1.append( carac );
		else if ( carac == ' ' )
			numSpaces1++;
	}
	for ( int i=0 ; i<key2.size() ; i++ )
	{
		carac = key2[ i ];
		if ( carac.isDigit() )
			numStr2.append( carac );
		else if ( carac == ' ' )
			numSpaces2++;
	}

	quint32 num1 = numStr1.toUInt();
	quint32 num2 = numStr2.toUInt();

	//qDebug() << QString::number(num1);
	//qDebug() << QString::number(num2);

	//qDebug() << QString::number(numSpaces1);
	//qDebug() << QString::number(numSpaces2);

	num1 /= numSpaces1;
	num2 /= numSpaces2;

	QString concat = serializeInt( num1 ) + serializeInt( num2 ) + key3;

	QByteArray md5 = QCryptographicHash::hash( concat.toAscii(), QCryptographicHash::Md5 );

	return QString( md5 );
}

QString QWsServer::serializeInt( quint32 number, quint8 nbBytes )
{
	QString bin;
	quint8 currentNbBytes = 0;
	while (number > 0 && currentNbBytes < nbBytes)
	{
		bin.prepend( QChar::fromAscii(number) );
		number = number >> 8;
		currentNbBytes++;
	}
	while (currentNbBytes < nbBytes)
	{
		bin.prepend( QChar::fromAscii(0) );
		currentNbBytes++;
	}
	return bin;
}
<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/1/27 13:16:25
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
constexpr int infty{10000000};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}
// ----- main() -----

int main()
{
  int H, N;
  cin >> H >> N;
  vector<int> A(N), B(N);
  for (auto i = 0; i < N; ++i)
  {
    cin >> A[i] >> B[i];
  }
  vector<int> dp(H + 1, infty);
  dp[0] = 0;
  for (auto j = 0; j < N; ++j)
  {
    for (auto i = 0; i < H; ++i)
    {
      ch_min(dp[min(H, i + A[j])], dp[i] + B[j]);
    }
  }
  cout << dp[H] << endl;
}
<commit_msg>tried E.cpp to 'E'<commit_after>#define DEBUG 1
/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/1/27 13:16:25
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
constexpr int infty{100'000'000};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}
// ----- main() -----

int main()
{
  int H, N;
  cin >> H >> N;
  vector<int> A(N), B(N);
  for (auto i = 0; i < N; ++i)
  {
    cin >> A[i] >> B[i];
  }
  vector<int> dp(H + 1, infty);
  dp[0] = 0;
  for (auto i = 0; i < H; ++i)
  {
    for (auto j = 0; j < N; ++j)
    {
      ch_min(dp[min(H, i + A[j])], dp[i] + B[j]);
    }
  }
#if DEBUG == 1
  for (auto i = 0; i <= H; ++i)
  {
    cerr << "dp[" << i << "] = " << dp[i] << endl;
  }
#endif
  // cout << dp[H] << endl;
}
<|endoftext|>


<commit_before>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "stock.hh"

namespace Rapicorn {

// == StockFile ==
struct StockFile {
  std::shared_ptr<IniFile> ifile_;
  String                   input_;
public:
  explicit StockFile       (Blob blob) : input_ (blob.name())          { ifile_ = std::make_shared<IniFile> (blob); }
  String   stock_element    (const String &stock_id, const String &what) { return ifile_->value_as_string (stock_id + "." + what); }
  String   dir_path        ()                                           { return Path::dirname (input_); }
  String   file_path       (const String &file)                         { return Path::join (dir_path(), file); }
  IniFile& ini_file        ()                                           { return *ifile_; }
};

// == Stock ==
static Mutex             stock_mutex;
static vector<StockFile> stock_files;

static void
init_stock_lib (const StringVector &args)
{
  const ScopedLock<Mutex> sl (stock_mutex);
  StockFile std_stock_file (Res ("@res Rapicorn/stock.ini").as<Blob>());
  if (!std_stock_file.ini_file().has_sections())
    fatal ("failed to load builtin: %s", "Rapicorn/stock.ini");
  stock_files.push_back (std_stock_file);
}
static InitHook _init_stock_lib ("core/50 Init Stock Lib", init_stock_lib);

Stock::Stock (const String &stock_id) :
  stock_id_ (stock_id)
{}

/// Retrieve and load the binary contents referred to by the "icon" attribute of @a stock_id.
String
Stock::icon() const
{
  const ScopedLock<Mutex> sl (stock_mutex);
  for (auto sf : stock_files)
    {
      String icon_source = sf.stock_element (stock_id_, "icon");
      if (!icon_source.empty())
        return "@res " + sf.file_path (icon_source);
    }
  errno = ENOENT;
  return String();
}

/// Retrieve the @a key attribute of @a stock_id as a string.
String
Stock::element (const String &key) const
{
  const ScopedLock<Mutex> sl (stock_mutex);
  for (auto sf : stock_files)
    {
      String s = sf.stock_element (stock_id_, key);
      if (!s.empty())
        return s;
    }
  return "";
}

/// Retrieve the "label" string attribute of @a stock_id.
String
Stock::label() const
{
  return element ("label");
}

/// Retrieve the "tooltip" string attribute of @a stock_id.
String
Stock::tooltip() const
{
  return element ("tooltip");
}

/// Retrieve the "accelerator" string attribute of @a stock_id.
String
Stock::accelerator() const
{
  return element ("accelerator");
}

/**
 * @class Stock
 * Stock resource retrieval facility.
 * The stock system provides a number of predefined labels, tooltips, accelerators and
 * icons out of the box, accessible via a specific identifier, the @a stock_id.
 */

} // Rapicorn
<commit_msg>UI: initialize stock_files on demand<commit_after>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "stock.hh"

namespace Rapicorn {

// == StockFile ==
struct StockFile {
  std::shared_ptr<IniFile> ifile_;
  String                   input_;
public:
  explicit StockFile       (Blob blob) : input_ (blob.name())          { ifile_ = std::make_shared<IniFile> (blob); }
  String   stock_element    (const String &stock_id, const String &what) { return ifile_->value_as_string (stock_id + "." + what); }
  String   dir_path        ()                                           { return Path::dirname (input_); }
  String   file_path       (const String &file)                         { return Path::join (dir_path(), file); }
  IniFile& ini_file        ()                                           { return *ifile_; }
};

// == Stock ==
static const vector<StockFile>&
get_stock_files()
{
  static const vector<StockFile> stock_files = []() {
    StockFile std_stock_file (Res ("@res Rapicorn/stock.ini").as<Blob>());
    if (!std_stock_file.ini_file().has_sections())
      fatal ("failed to load builtin: %s", "Rapicorn/stock.ini");
    vector<StockFile> stock_files;
    stock_files.push_back (std_stock_file);
    return stock_files;
  }();
  return stock_files;
}

Stock::Stock (const String &stock_id) :
  stock_id_ (stock_id)
{}

/// Retrieve and load the binary contents referred to by the "icon" attribute of @a stock_id.
String
Stock::icon() const
{
  for (auto sf : get_stock_files())
    {
      String icon_source = sf.stock_element (stock_id_, "icon");
      if (!icon_source.empty())
        return "@res " + sf.file_path (icon_source);
    }
  errno = ENOENT;
  return String();
}

/// Retrieve the @a key attribute of @a stock_id as a string.
String
Stock::element (const String &key) const
{
  for (auto sf : get_stock_files())
    {
      String s = sf.stock_element (stock_id_, key);
      if (!s.empty())
        return s;
    }
  return "";
}

/// Retrieve the "label" string attribute of @a stock_id.
String
Stock::label() const
{
  return element ("label");
}

/// Retrieve the "tooltip" string attribute of @a stock_id.
String
Stock::tooltip() const
{
  return element ("tooltip");
}

/// Retrieve the "accelerator" string attribute of @a stock_id.
String
Stock::accelerator() const
{
  return element ("accelerator");
}

/**
 * @class Stock
 * Stock resource retrieval facility.
 * The stock system provides a number of predefined labels, tooltips, accelerators and
 * icons out of the box, accessible via a specific identifier, the @a stock_id.
 */

} // Rapicorn
<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/6/23 5:42:51
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- ReadGraph -----
// Referring to ymatsux-san's source code: https://atcoder.jp/contests/abc138/submissions/7016619

struct Edge
{
  int src, dst, id, rev;
  // ll cost;
  Edge() {}
  Edge(int src, int dst, int id, int rev) : src{src}, dst{dst}, id{id}, rev{rev} {}

  void added_edge(vector<vector<Edge>> &V)
  {
    V[src].push_back(*this);
  }

  void added_rev(vector<vector<Edge>> &V)
  {
    V[dst].push_back(rev_edge());
  }

  Edge rev_edge()
  {
    Edge edge{*this};
    swap(edge.src, edge.dst);
    swap(edge.id, edge.rev);
    return edge;
  }
};

enum class GraphType
{
  Undirected,
  Directed,
  RevEdge,
};

tuple<vector<vector<Edge>>, vector<Edge>> ReadGraphWithEdges(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  vector<vector<Edge>> V(N);
  vector<Edge> E;
  for (auto i = 0; i < M; ++i)
  {
    int v, w;
    cin >> v >> w;
    if (is_one_indexed)
    {
      --v;
      --w;
    }
    switch (type)
    {
    case GraphType::Undirected:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      break;
    }
    case GraphType::Directed:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      E.push_back(edge);
      break;
    }
    case GraphType::RevEdge:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size()) + 1};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      E.push_back(edge.rev_edge());
      break;
    }
    default:
      break;
    }
  }
  return make_tuple(V, E);
}

vector<vector<Edge>> ReadGraph(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return get<0>(ReadGraphWithEdges(N, M, type, is_one_indexed));
}

tuple<vector<vector<Edge>>, vector<Edge>> ReadTreeWithEdges(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraphWithEdges(N, N - 1, type, is_one_indexed);
}

vector<vector<Edge>> ReadTree(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraph(N, N - 1, type, is_one_indexed);
}

// ----- Solve -----

chrono::system_clock::time_point time_start = chrono::system_clock::now();

void TimeStamp()
{
  cerr << chrono::duration_cast<std::chrono::milliseconds>(chrono::system_clock::now() - time_start).count() << endl;
}

struct SubTree
{
  ll id, size;
};

class Solve
{
  ll N, id;
  vector<queue<SubTree>> Q;
  vector<ll> C;
  vector<vector<Edge>> V;
  vector<vector<ll>> S;
  vector<ll> color_to_count;

public:
  Solve(ll N) : N{N}, id{0}, Q(N), C(N), S(N), color_to_count(N, 0)
  {
    for (auto i{0}; i < N; ++i)
    {
      cin >> C[i];
      C[i]--;
      color_to_count[C[i]]++;
    }
    V = ReadTree(N);
  }

  void flush()
  {
    dfs();
    for (auto i{0}; i < N; ++i)
    {
      auto sum{accumulate(S[i].begin(), S[i].end(), 0)};
      S[i].push_back(N - sum - color_to_count[i]);
      ll ans{0};
      for (auto e : S[i])
      {
        ans += e * (e + 1) / 2;
      }
#if DEBUG == 1
      cerr << "S[" << i << "] : ";
      for (auto e : S[i])
      {
        cerr << e << ", ";
      }
      cerr << endl;
#endif
      cout << N * (N + 1) / 2 - ans << endl;
    }
  }

private:
  ll dfs(ll src = 0, ll parent = -1)
  {
#if DEBUG == 1
    TimeStamp();
    cerr << "dfs(" << src << ")" << endl;
#endif
    auto src_id{id++};
    auto &subtree_queue{Q[C[src]]};
    for (auto const &e : V[src])
    {
      if (e.dst == parent)
      {
        continue;
      }
      auto colorless_tree_size{dfs(e.dst, src)};
      while (!subtree_queue.empty() && subtree_queue.front().id > src_id)
      {
        colorless_tree_size -= subtree_queue.front().size;
        subtree_queue.pop();
      }
      S[C[src]].push_back(colorless_tree_size);
    }
    auto subtree_size{id - src_id};
    subtree_queue.push(SubTree{src_id, subtree_size});
    return subtree_size;
  }
};

// ----- main() -----

int main()
{
  ll N;
  cin >> N;
  Solve solve(N);
  solve.flush();
}
<commit_msg>tried F.cpp to 'F'<commit_after>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/6/23 5:42:51
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- ReadGraph -----
// Referring to ymatsux-san's source code: https://atcoder.jp/contests/abc138/submissions/7016619

struct Edge
{
  int src, dst, id, rev;
  // ll cost;
  Edge() {}
  Edge(int src, int dst, int id, int rev) : src{src}, dst{dst}, id{id}, rev{rev} {}

  void added_edge(vector<vector<Edge>> &V)
  {
    V[src].push_back(*this);
  }

  void added_rev(vector<vector<Edge>> &V)
  {
    V[dst].push_back(rev_edge());
  }

  Edge rev_edge()
  {
    Edge edge{*this};
    swap(edge.src, edge.dst);
    swap(edge.id, edge.rev);
    return edge;
  }
};

enum class GraphType
{
  Undirected,
  Directed,
  RevEdge,
};

tuple<vector<vector<Edge>>, vector<Edge>> ReadGraphWithEdges(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  vector<vector<Edge>> V(N);
  vector<Edge> E;
  for (auto i = 0; i < M; ++i)
  {
    int v, w;
    cin >> v >> w;
    if (is_one_indexed)
    {
      --v;
      --w;
    }
    switch (type)
    {
    case GraphType::Undirected:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      break;
    }
    case GraphType::Directed:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      E.push_back(edge);
      break;
    }
    case GraphType::RevEdge:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size()) + 1};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      E.push_back(edge.rev_edge());
      break;
    }
    default:
      break;
    }
  }
  return make_tuple(V, E);
}

vector<vector<Edge>> ReadGraph(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return get<0>(ReadGraphWithEdges(N, M, type, is_one_indexed));
}

tuple<vector<vector<Edge>>, vector<Edge>> ReadTreeWithEdges(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraphWithEdges(N, N - 1, type, is_one_indexed);
}

vector<vector<Edge>> ReadTree(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraph(N, N - 1, type, is_one_indexed);
}

// ----- Solve -----

chrono::system_clock::time_point time_start = chrono::system_clock::now();

void TimeStamp()
{
  cout << chrono::duration_cast<std::chrono::milliseconds>(chrono::system_clock::now() - time_start).count() << endl;
}

struct SubTree
{
  ll id, size;
};

class Solve
{
  ll N, id;
  vector<queue<SubTree>> Q;
  vector<ll> C;
  vector<vector<Edge>> V;
  vector<vector<ll>> S;
  vector<ll> color_to_count;

public:
  Solve(ll N) : N{N}, id{0}, Q(N), C(N), S(N), color_to_count(N, 0)
  {
    for (auto i{0}; i < N; ++i)
    {
      cin >> C[i];
      C[i]--;
      color_to_count[C[i]]++;
    }
    V = ReadTree(N);
  }

  void flush()
  {
    dfs();
    for (auto i{0}; i < N; ++i)
    {
      auto sum{accumulate(S[i].begin(), S[i].end(), 0)};
      S[i].push_back(N - sum - color_to_count[i]);
      ll ans{0};
      for (auto e : S[i])
      {
        ans += e * (e + 1) / 2;
      }
#if DEBUG == 1
      cerr << "S[" << i << "] : ";
      for (auto e : S[i])
      {
        cerr << e << ", ";
      }
      cerr << endl;
#endif
      cout << N * (N + 1) / 2 - ans << endl;
    }
  }

private:
  ll dfs(ll src = 0, ll parent = -1)
  {
#if DEBUG == 1
    TimeStamp();
    cerr << "dfs(" << src << ")" << endl;
#endif
    auto src_id{id++};
    auto &subtree_queue{Q[C[src]]};
    for (auto const &e : V[src])
    {
      if (e.dst == parent)
      {
        continue;
      }
      auto colorless_tree_size{dfs(e.dst, src)};
      while (!subtree_queue.empty() && subtree_queue.front().id > src_id)
      {
        colorless_tree_size -= subtree_queue.front().size;
        subtree_queue.pop();
      }
      S[C[src]].push_back(colorless_tree_size);
    }
    auto subtree_size{id - src_id};
    subtree_queue.push(SubTree{src_id, subtree_size});
    return subtree_size;
  }
};

// ----- main() -----

int main()
{
  ll N;
  cin >> N;
  Solve solve(N);
  solve.flush();
}
<|endoftext|>


<commit_before>//
//  IndexedMesh.cpp
//  G3MiOSSDK
//
//  Created by José Miguel S N on 22/06/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include <stdlib.h>

#include "IndexedMesh.hpp"
#include "Box.hpp"
#include "GL.hpp"
#include "IFloatBuffer.hpp"
#include "IIntBuffer.hpp"

IndexedMesh::~IndexedMesh() {
  if (_owner){
    delete _vertices;
    delete _indices;
    if (_colors != NULL) delete _colors;
  }

  if (_extent != NULL) delete _extent;
  if (_translationMatrix != NULL) delete _translationMatrix;
}

IndexedMesh::IndexedMesh(const int primitive,
                         bool owner,
                         const Vector3D& center,
                         IFloatBuffer* vertices,
                         IIntBuffer* indices,
                         float lineWidth,
                         const Color* flatColor,
                         IFloatBuffer* colors,
                         const float colorsIntensity) :
_primitive(primitive),
_owner(owner),
_vertices(vertices),
_indices(indices),
_flatColor(flatColor),
_colors(colors),
_colorsIntensity(colorsIntensity),
_extent(NULL),
_center(center),
_translationMatrix(( center.isNan() || center.isZero() )
                    ? NULL
                    : new MutableMatrix44D(MutableMatrix44D::createTranslationMatrix(center)) ),
_lineWidth(lineWidth)
{
}

void IndexedMesh::render(const RenderContext* rc) const {
  GL *gl = rc->getGL();

  gl->enableVerticesPosition();

  if (_colors == NULL) {
    gl->disableVertexColor();
  }
  else {
    gl->enableVertexColor(_colors, _colorsIntensity);
  }

  if (_flatColor == NULL) {
    gl->disableVertexFlatColor();
  }
  else {
    gl->enableVertexFlatColor(*_flatColor, _colorsIntensity);
  }

  gl->vertexPointer(3, 0, _vertices);

  gl->lineWidth(_lineWidth);

  if (_translationMatrix != NULL){
    gl->pushMatrix();
    gl->multMatrixf(*_translationMatrix);
  }

  if (_primitive == GLPrimitive::triangleStrip()) {
    gl->drawTriangleStrip(_indices);
  }
  else if (_primitive == GLPrimitive::lines()) {
    gl->drawLines(_indices);
  }
  else if (_primitive == GLPrimitive::lineStrip()) {
    gl->drawLineStrip(_indices);
  }
  else if (_primitive == GLPrimitive::lineLoop()) {
    gl->drawLineLoop(_indices);
  }
  else if (_primitive == GLPrimitive::points()) {
    gl->drawPoints(_indices);
  }

  if (_translationMatrix != NULL) {
    gl->popMatrix();
  }

  gl->disableVerticesPosition();
}

Extent* IndexedMesh::computeExtent() const {

  const int vertexCount = getVertexCount();

  if (vertexCount <= 0) {
    return NULL;
  }

  double minx=1e10, miny=1e10, minz=1e10;
  double maxx=-1e10, maxy=-1e10, maxz=-1e10;

  for (int i=0; i < vertexCount; i++) {
    const int p = i * 3;

    const double x = _vertices->get(p  ) + _center._x;
    const double y = _vertices->get(p+1) + _center._y;
    const double z = _vertices->get(p+2) + _center._z;

    if (x < minx) minx = x;
    if (x > maxx) maxx = x;

    if (y < miny) miny = y;
    if (y > maxy) maxy = y;

    if (z < minz) minz = z;
    if (z > maxz) maxz = z;
  }

  return new Box(Vector3D(minx, miny, minz), Vector3D(maxx, maxy, maxz));
}

Extent* IndexedMesh::getExtent() const {
  if (_extent == NULL) {
    _extent = computeExtent();
  }
  return _extent;
}

const Vector3D IndexedMesh::getVertex(int i) const {
  const int p = i * 3;
  return Vector3D(_vertices->get(p  ) + _center._x,
                  _vertices->get(p+1) + _center._y,
                  _vertices->get(p+2) + _center._z);
}

int IndexedMesh::getVertexCount() const {
  return _vertices->size() / 3;
}
<commit_msg>fixed a memory leak<commit_after>//
//  IndexedMesh.cpp
//  G3MiOSSDK
//
//  Created by José Miguel S N on 22/06/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include <stdlib.h>

#include "IndexedMesh.hpp"
#include "Box.hpp"
#include "GL.hpp"
#include "IFloatBuffer.hpp"
#include "IIntBuffer.hpp"

IndexedMesh::~IndexedMesh() {
  if (_owner){
    delete _vertices;
    delete _indices;
    delete _colors;
    delete _flatColor;
  }

  if (_extent != NULL) delete _extent;
  if (_translationMatrix != NULL) delete _translationMatrix;
}

IndexedMesh::IndexedMesh(const int primitive,
                         bool owner,
                         const Vector3D& center,
                         IFloatBuffer* vertices,
                         IIntBuffer* indices,
                         float lineWidth,
                         const Color* flatColor,
                         IFloatBuffer* colors,
                         const float colorsIntensity) :
_primitive(primitive),
_owner(owner),
_vertices(vertices),
_indices(indices),
_flatColor(flatColor),
_colors(colors),
_colorsIntensity(colorsIntensity),
_extent(NULL),
_center(center),
_translationMatrix(( center.isNan() || center.isZero() )
                    ? NULL
                    : new MutableMatrix44D(MutableMatrix44D::createTranslationMatrix(center)) ),
_lineWidth(lineWidth)
{
}

void IndexedMesh::render(const RenderContext* rc) const {
  GL *gl = rc->getGL();

  gl->enableVerticesPosition();

  if (_colors == NULL) {
    gl->disableVertexColor();
  }
  else {
    gl->enableVertexColor(_colors, _colorsIntensity);
  }

  if (_flatColor == NULL) {
    gl->disableVertexFlatColor();
  }
  else {
    gl->enableVertexFlatColor(*_flatColor, _colorsIntensity);
  }

  gl->vertexPointer(3, 0, _vertices);

  gl->lineWidth(_lineWidth);

  if (_translationMatrix != NULL){
    gl->pushMatrix();
    gl->multMatrixf(*_translationMatrix);
  }

  if (_primitive == GLPrimitive::triangleStrip()) {
    gl->drawTriangleStrip(_indices);
  }
  else if (_primitive == GLPrimitive::lines()) {
    gl->drawLines(_indices);
  }
  else if (_primitive == GLPrimitive::lineStrip()) {
    gl->drawLineStrip(_indices);
  }
  else if (_primitive == GLPrimitive::lineLoop()) {
    gl->drawLineLoop(_indices);
  }
  else if (_primitive == GLPrimitive::points()) {
    gl->drawPoints(_indices);
  }

  if (_translationMatrix != NULL) {
    gl->popMatrix();
  }

  gl->disableVerticesPosition();
}

Extent* IndexedMesh::computeExtent() const {

  const int vertexCount = getVertexCount();

  if (vertexCount <= 0) {
    return NULL;
  }

  double minx=1e10, miny=1e10, minz=1e10;
  double maxx=-1e10, maxy=-1e10, maxz=-1e10;

  for (int i=0; i < vertexCount; i++) {
    const int p = i * 3;

    const double x = _vertices->get(p  ) + _center._x;
    const double y = _vertices->get(p+1) + _center._y;
    const double z = _vertices->get(p+2) + _center._z;

    if (x < minx) minx = x;
    if (x > maxx) maxx = x;

    if (y < miny) miny = y;
    if (y > maxy) maxy = y;

    if (z < minz) minz = z;
    if (z > maxz) maxz = z;
  }

  return new Box(Vector3D(minx, miny, minz), Vector3D(maxx, maxy, maxz));
}

Extent* IndexedMesh::getExtent() const {
  if (_extent == NULL) {
    _extent = computeExtent();
  }
  return _extent;
}

const Vector3D IndexedMesh::getVertex(int i) const {
  const int p = i * 3;
  return Vector3D(_vertices->get(p  ) + _center._x,
                  _vertices->get(p+1) + _center._y,
                  _vertices->get(p+2) + _center._z);
}

int IndexedMesh::getVertexCount() const {
  return _vertices->size() / 3;
}
<|endoftext|>


<commit_before>//===-- HexagonMCTargetDesc.cpp - Cell Hexagon Target Descriptions --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Cell Hexagon specific target descriptions.
//
//===----------------------------------------------------------------------===//

#include "HexagonMCTargetDesc.h"
#include "HexagonMCAsmInfo.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/MC/MCCodeGenInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"

#define GET_INSTRINFO_MC_DESC
#include "HexagonGenInstrInfo.inc"

#define GET_SUBTARGETINFO_MC_DESC
#include "HexagonGenSubtargetInfo.inc"

#define GET_REGINFO_MC_DESC
#include "HexagonGenRegisterInfo.inc"

using namespace llvm;

static MCInstrInfo *createHexagonMCInstrInfo() {
  MCInstrInfo *X = new MCInstrInfo();
  InitHexagonMCInstrInfo(X);
  return X;
}

static MCRegisterInfo *createHexagonMCRegisterInfo(StringRef TT) {
  MCRegisterInfo *X = new MCRegisterInfo();
  InitHexagonMCRegisterInfo(X, Hexagon::R0);
  return X;
}

static MCSubtargetInfo *createHexagonMCSubtargetInfo(StringRef TT,
                                                     StringRef CPU,
                                                     StringRef FS) {
  MCSubtargetInfo *X = new MCSubtargetInfo();
  InitHexagonMCSubtargetInfo(X, TT, CPU, FS);
  return X;
}

static MCAsmInfo *createHexagonMCAsmInfo(const Target &T, StringRef TT) {
  MCAsmInfo *MAI = new HexagonMCAsmInfo(T, TT);

  // VirtualFP = (R30 + #0).
  MachineLocation Dst(MachineLocation::VirtualFP);
  MachineLocation Src(Hexagon::R30, 0);
  MAI->addInitialFrameState(0, Dst, Src);

  return MAI;
}

static MCCodeGenInfo *createHexagonMCCodeGenInfo(StringRef TT, Reloc::Model RM,
                                             CodeModel::Model CM,
                                             CodeGenOpt::Level OL) {
  MCCodeGenInfo *X = new MCCodeGenInfo();
  // For the time being, use static relocations, since there's really no
  // support for PIC yet.
  X->InitMCCodeGenInfo(Reloc::Static, CM, OL);
  return X;
}

// Force static initialization.
extern "C" void LLVMInitializeHexagonTargetMC() {
  // Register the MC asm info.
  RegisterMCAsmInfoFn X(TheHexagonTarget, createHexagonMCAsmInfo);

  // Register the MC codegen info.
  TargetRegistry::RegisterMCCodeGenInfo(TheHexagonTarget,
                                        createHexagonMCCodeGenInfo);

  // Register the MC instruction info.
  TargetRegistry::RegisterMCInstrInfo(TheHexagonTarget, createHexagonMCInstrInfo);

  // Register the MC register info.
  TargetRegistry::RegisterMCRegInfo(TheHexagonTarget,
                                    createHexagonMCRegisterInfo);

  // Register the MC subtarget info.
  TargetRegistry::RegisterMCSubtargetInfo(TheHexagonTarget,
                                          createHexagonMCSubtargetInfo);
}
<commit_msg>Fix typo in file header.<commit_after>//===-- HexagonMCTargetDesc.cpp - Cell Hexagon Target Descriptions --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Hexagon specific target descriptions.
//
//===----------------------------------------------------------------------===//

#include "HexagonMCTargetDesc.h"
#include "HexagonMCAsmInfo.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/MC/MCCodeGenInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"

#define GET_INSTRINFO_MC_DESC
#include "HexagonGenInstrInfo.inc"

#define GET_SUBTARGETINFO_MC_DESC
#include "HexagonGenSubtargetInfo.inc"

#define GET_REGINFO_MC_DESC
#include "HexagonGenRegisterInfo.inc"

using namespace llvm;

static MCInstrInfo *createHexagonMCInstrInfo() {
  MCInstrInfo *X = new MCInstrInfo();
  InitHexagonMCInstrInfo(X);
  return X;
}

static MCRegisterInfo *createHexagonMCRegisterInfo(StringRef TT) {
  MCRegisterInfo *X = new MCRegisterInfo();
  InitHexagonMCRegisterInfo(X, Hexagon::R0);
  return X;
}

static MCSubtargetInfo *createHexagonMCSubtargetInfo(StringRef TT,
                                                     StringRef CPU,
                                                     StringRef FS) {
  MCSubtargetInfo *X = new MCSubtargetInfo();
  InitHexagonMCSubtargetInfo(X, TT, CPU, FS);
  return X;
}

static MCAsmInfo *createHexagonMCAsmInfo(const Target &T, StringRef TT) {
  MCAsmInfo *MAI = new HexagonMCAsmInfo(T, TT);

  // VirtualFP = (R30 + #0).
  MachineLocation Dst(MachineLocation::VirtualFP);
  MachineLocation Src(Hexagon::R30, 0);
  MAI->addInitialFrameState(0, Dst, Src);

  return MAI;
}

static MCCodeGenInfo *createHexagonMCCodeGenInfo(StringRef TT, Reloc::Model RM,
                                             CodeModel::Model CM,
                                             CodeGenOpt::Level OL) {
  MCCodeGenInfo *X = new MCCodeGenInfo();
  // For the time being, use static relocations, since there's really no
  // support for PIC yet.
  X->InitMCCodeGenInfo(Reloc::Static, CM, OL);
  return X;
}

// Force static initialization.
extern "C" void LLVMInitializeHexagonTargetMC() {
  // Register the MC asm info.
  RegisterMCAsmInfoFn X(TheHexagonTarget, createHexagonMCAsmInfo);

  // Register the MC codegen info.
  TargetRegistry::RegisterMCCodeGenInfo(TheHexagonTarget,
                                        createHexagonMCCodeGenInfo);

  // Register the MC instruction info.
  TargetRegistry::RegisterMCInstrInfo(TheHexagonTarget, createHexagonMCInstrInfo);

  // Register the MC register info.
  TargetRegistry::RegisterMCRegInfo(TheHexagonTarget,
                                    createHexagonMCRegisterInfo);

  // Register the MC subtarget info.
  TargetRegistry::RegisterMCSubtargetInfo(TheHexagonTarget,
                                          createHexagonMCSubtargetInfo);
}
<|endoftext|>


<commit_before>#include "main_window.hpp"
#include "ui_main_window.h"

#include "vec.hpp"
#include "mat.hpp"
#include "trafo_mats.hpp"

#include <QPainter>
#include <QTimer>

struct MainWindow::Impl
{
  Ui::MainWindow ui;
  double angle{};
};

MainWindow::MainWindow(QWidget *parent)
  : QWidget(parent)
  , m( std::make_unique<Impl>() )
{
  m->ui.setupUi(this);
  auto timer = new QTimer(this);
  connect( timer, &QTimer::timeout, this, [this](){ m->angle += 0.01; update(); } );
  timer->start(20);
}

void MainWindow::paintEvent( QPaintEvent * )
{
  std::array<cu::Vec<double,4>,8> points =
  {{
    { 1, 1, 1, 1},
    { 1, 1,-1, 1},
    { 1,-1, 1, 1},
    { 1,-1,-1, 1},
    {-1, 1, 1, 1},
    {-1, 1,-1, 1},
    {-1,-1, 1, 1},
    {-1,-1,-1, 1}
  }};
  const auto shiftMat =
          cu::makeTranslationMat( cu::makeVec(0.,0.,-6.) );
  const auto rotMat =
          cu::makeExtendedMat(
          cu::makeRotationMat( cu::makeVec( -0.3,0.,0. ) ) *
          cu::makeRotationMat( m->angle*cu::makeVec(0.,1.,0.) ) );
  const auto width = this->width();
  const auto height = this->height();
  const auto scaleFactor = std::min( width, height );
  const auto systemMatrix =
          shiftMat *
          rotMat;
  std::array<cu::Vec<double,2>,8> transformedPoints;
  for ( std::size_t i = 0; i!= points.size(); ++i )
  {
      const auto vec = systemMatrix * points[i];
      transformedPoints[i] = { 1.5*scaleFactor * vec[0] / -vec[2] + 0.5*width,
                               1.5*scaleFactor * vec[1] / -vec[2] + 0.5*height };
  }

  QPainter painter(this);
  painter.fillRect( this->rect(), Qt::black );
  painter.setPen( Qt::white );
  for ( std::size_t i = 0; i!= points.size(); ++i )
  {
      constexpr std::size_t bits[] = { 1, 2, 4 };
      for ( auto bit : bits )
      {
          if ( i & bit )
              continue;
          const auto & P = transformedPoints[ i       ];
          const auto & Q = transformedPoints[ i | bit ];
          painter.drawLine( QPointF( P[0], P[1] ), QPointF( Q[0], Q[1] ) );
      }
  }
}

MainWindow::~MainWindow() = default;
<commit_msg>Changed use of double precision to single precision.<commit_after>#include "main_window.hpp"
#include "ui_main_window.h"

#include "vec.hpp"
#include "mat.hpp"
#include "trafo_mats.hpp"

#include <QPainter>
#include <QTimer>

struct MainWindow::Impl
{
  Ui::MainWindow ui;
  float angle{};
};

MainWindow::MainWindow(QWidget *parent)
  : QWidget(parent)
  , m( std::make_unique<Impl>() )
{
  m->ui.setupUi(this);
  auto timer = new QTimer(this);
  connect( timer, &QTimer::timeout, this, [this](){ m->angle += 0.01; update(); } );
  timer->start(20);
}

void MainWindow::paintEvent( QPaintEvent * )
{
  std::array<cu::Vec<float,4>,8> points =
  {{
    { 1, 1, 1, 1},
    { 1, 1,-1, 1},
    { 1,-1, 1, 1},
    { 1,-1,-1, 1},
    {-1, 1, 1, 1},
    {-1, 1,-1, 1},
    {-1,-1, 1, 1},
    {-1,-1,-1, 1}
  }};
  const auto shiftMat =
          cu::makeTranslationMat( cu::makeVec(0.f,0.f,-6.f) );
  const auto rotMat =
          cu::makeExtendedMat(
          cu::makeRotationMat( cu::makeVec( -0.3f,0.f,0.f ) ) *
          cu::makeRotationMat( m->angle*cu::makeVec(0.f,1.f,0.f) ) );
  const auto width = this->width();
  const auto height = this->height();
  const auto scaleFactor = std::min( width, height );
  const auto systemMatrix =
          shiftMat *
          rotMat;
  std::array<cu::Vec<float,2>,8> transformedPoints;
  for ( std::size_t i = 0; i!= points.size(); ++i )
  {
      const auto vec = systemMatrix * points[i];
      transformedPoints[i] = { 1.5f*scaleFactor * vec[0] / -vec[2] + 0.5f*width,
                               1.5f*scaleFactor * vec[1] / -vec[2] + 0.5f*height };
  }

  QPainter painter(this);
  painter.fillRect( this->rect(), Qt::black );
  painter.setPen( Qt::white );
  for ( std::size_t i = 0; i!= points.size(); ++i )
  {
      for ( auto bit : { 1, 2, 4 } )
      {
          if ( i & bit )
              continue;
          const auto & P = transformedPoints[ i       ];
          const auto & Q = transformedPoints[ i | bit ];
          painter.drawLine( QPointF( P[0], P[1] ), QPointF( Q[0], Q[1] ) );
      }
  }
}

MainWindow::~MainWindow() = default;
<|endoftext|>


<commit_before>#include "main_window.h"
#include "ui_mainwindow.h"
#include "quca.hpp"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
    //, ui(new Ui::MainWindow)
{
    setWindowTitle("Quite");
    slide_timer = new QTimer();

    qDebug() << "Main Window Started";
    setGeometry(QRect(0, 0, WIDTH, HEIGHT));
    QSizePolicy pol(QSizePolicy::Preferred, QSizePolicy::Preferred);
    pol.setHorizontalStretch(0);
    pol.setVerticalStretch(0);
    setSizePolicy(pol);
    layout()->setMargin(11);
    layout()->setSpacing(6);
    qDebug() << "X";

    // Setup the managers
    image_manager = new ImageManager(this);
    video_manager = new VideoManager(this);

    // Setup the Menu
    //this->menuBar()->setGeometry(0, 0, WIDTH, 22);
    QMenu* browse_menu = menuBar()->addMenu(tr("&Browse"));
    QAction *file = browse_menu->addAction(tr("F&ile")),
             *folder = browse_menu->addAction(tr("F&older"));
    connect(file, SIGNAL(triggered()), this, SLOT(browseForFile()));
    connect(folder, SIGNAL(triggered()), this, SLOT(browseForFolder()));
    //*/

    // Setup the StatusBar
    for(QCheckBox* check : image_manager->getChecks()) {
        QMainWindow::connect(check, SIGNAL(clicked()), this, SLOT(reloadFolder()));
        statusBar()->addWidget(check);
        status_bar_widgets.append(check);
    }
    for(QCheckBox* check : video_manager->getChecks()) {
        QMainWindow::connect(check, SIGNAL(clicked()), this, SLOT(reloadFolder()));
        statusBar()->addWidget(check);
        status_bar_widgets.append(check);
    }

    status_bar_speed = new QLabel();
    statusBar()->addWidget(status_bar_speed);
    status_bar_widgets.append(status_bar_speed);

    slideshow_button = new QPushButton(tr("Slide"));
    slideshow_button->setFocusPolicy(Qt::NoFocus);
    statusBar()->addWidget(slideshow_button);
    status_bar_widgets.append(slideshow_button);

    slideshow_time = new QSpinBox();
    slideshow_time->setValue(3);
    slideshow_time->setSuffix("s");
    slideshow_time->setRange(1, 60);
    slideshow_time->setFocusPolicy(Qt::NoFocus);
    statusBar()->addWidget(slideshow_time);
    status_bar_widgets.append(slideshow_time);

    random_order = new QCheckBox(tr("Random"));
    statusBar()->addWidget(random_order);
    status_bar_widgets.append(random_order);

    volume_dial = new QDial();
    volume_dial->setFocusPolicy(Qt::NoFocus);
    volume_dial->setMinimum(0);
    volume_dial->setMaximum(100);
    volume_dial->setNotchesVisible(true);
    volume_dial->setSingleStep(5);
    volume_dial->setBaseSize(20, 20);
    volume_dial->setMaximumSize(QSize(30,30));
    volume_dial->setWrapping(false); //WTF does this do?
    statusBar()->addWidget(volume_dial);
    status_bar_widgets.append(volume_dial);

    status_bar_text = new QLabel();
    status_bar_text->setAlignment(Qt::AlignRight);
    statusBar()->addWidget(status_bar_text);
    status_bar_widgets.append(status_bar_text);

    connect(random_order, SIGNAL(clicked()), this, SLOT(reloadFolder()));
    connect(slideshow_button, SIGNAL(clicked()), this, SLOT(slideshowButton()));
    connect(slide_timer, SIGNAL(timeout()), this, SLOT(nextItemWhenConvenient()));
    connect(slideshow_time, SIGNAL(valueChanged(int)), this, SLOT(restartSlideshow(int)));
    connect(volume_dial, SIGNAL(valueChanged(int)), this, SLOT(volumeChange(int)));

    for(QWidget* widget : status_bar_widgets)
        widget->setDisabled(true);

    qDebug() << "mainWindow created";
}

// Destructor
MainWindow::~MainWindow()
{
    qDebug() << "Destroying mainWindow";

    delete slide_timer;

    qDebug() << "Destroyed mainWindow";
}

// Start or stop the slideshow
void MainWindow::slideshowButton()
{
    qDebug() << "Slideshow Button";
    if(slide_timer->isActive()) {
        stopSlideshow();
        slideshow_button->setText("Slide");
    } else {
        startSlideshow();
        slideshow_button->setText("Stop");
    }
}

// Call 'loadFolder' again on the current folder (& current file)
void MainWindow::reloadFolder()
{
    qDebug() << "reloading folder";
    if(list_index>=0 && list_index<list.size())
        loadFolder(this->folder, list.at(list_index));
    else
        loadFolder(this->folder);
}

// Read a folder's files
void MainWindow::loadFolder(QString folder, QString file)
{
    qDebug() << "Loading Folder " << folder;
    QStringList filetypes_want;
    image_manager->addCheckedFiletypesTo(filetypes_want);
    video_manager->addCheckedFiletypesTo(filetypes_want);

    // If there are no checked filetypes
    if(filetypes_want.size()==0) {
        clearItem(); return; }

    // Check to see if the file we want is the same as is already loaded to avoid reloading it.
    bool sameFile =
            //Same folder
            this->folder==folder &&
            // Same file
            (
                list_index>0 &&
                list.length()>list_index &&
                file==list.at(list_index)
            ) &&
            // Extension checkbox for this file is checked
            filetypes_want.contains(QString("*.").append(QFileInfo(file).suffix()));

    // Set the folder & load the files
    this->folder = folder;
    list = QDir(folder).entryList(filetypes_want);

    // If there are no files
    if(list.length()==0) {
        clearItem(); return; }

    qDebug() << "Files: " << list.size();

    // Sort (or anti-sort) the list
    if(random_order->isChecked())
        std::random_shuffle(list.begin(), list.end());
    else
        QUnicodeCollationAlgorithm::collatorKeySort(list);

    // Determine if this was a reload, in which case we should not reload the current item
    if(sameFile) {
        qDebug() << "Reloading same file, so not re-starting it";
        return;
    }

    // Set the current file's index in the list
    if(file=="" || list.indexOf(file,0)<0)
        list_index = 0;
    else
        list_index = list.indexOf(file,0);

    for(QWidget* widget : status_bar_widgets)
        widget->setDisabled(false);

    loadItem();
}

void MainWindow::browseForFile()
{
    QString file = QFileDialog::getOpenFileName(this); //TODO filetype filtering
    QFileInfo fileinfo(file);
    if(fileinfo.isDir())
        loadFolder(fileinfo.filePath());
    else
        loadFolder(fileinfo.absoluteDir().absolutePath(), fileinfo.fileName());
}

void MainWindow::browseForFolder()
{
    loadFolder(QFileDialog::getExistingDirectory(this));
}

void MainWindow::wheelEvent(QWheelEvent *event)
{
    qDebug() << "WheelEvent";
    if (event->modifiers().testFlag(Qt::ControlModifier)) {
        //Zoom
    } else if (event->modifiers().testFlag(Qt::AltModifier)) {
        if(event->delta()>0)
            current_manager->faster();
        else
            current_manager->slower();
    } else {
        if(event->delta()<0)
            nextItem();
        else
            prevItem();
    }

}

void MainWindow::mousePressEvent(QMouseEvent * me)
{
    return;
    if(me->button()==Qt::LeftButton)
        nextItem();
    else if(me->button()==Qt::RightButton)
        prevItem();
}

void MainWindow::keyPressEvent(QKeyEvent * e)
{
    e->accept();
    switch (e->key()) {
        case Qt::Key_Right:
            nextItem();
            break;
        case Qt::Key_Left:
            prevItem();
            break;
        case Qt::Key_Plus:
            current_manager->faster();
            break;
        case Qt::Key_Minus:
            current_manager->slower();
            break;
        case Qt::Key_0:
            setSpeed();
            break;
        case Qt::Key_AsciiTilde:
            startSlideshow();
            return;
        case Qt::Key_Escape:
            stopSlideshow();
            return;
        case Qt::Key_Space:
            slideshowButton();
            return;
        case Qt::Key_P:
            if(current_manager->togglePause())
                stopSlideshow();
            else if(slide_timer->isActive())
                restartSlideshow();
            return;
        default:
            return;
    }
    if(slide_timer->isActive())
        restartSlideshow();
}

void MainWindow::nextItem()
{
    qDebug() << "nextItem";
    ++list_index;
    if(list_index==list.size())
        list_index = 0;
    loadItem();
}

void MainWindow::prevItem()
{
    qDebug() << "prevItem";
    if(list_index==0)
        list_index = list.size();
    --list_index;
    loadItem();
}

void MainWindow::setSpeed(double d)
{
    qDebug() << "setSpeed " << d;
    current_manager->setSpeed(d);
    status_bar_speed->setText(QString("%1x").arg(d/100.0));
}

void MainWindow::startSlideshow()
{
    qDebug() << "starting slideshow";
    slide_timer->start(slideshow_time->value() * 1000);
    //this->showFullScreen();
}

void MainWindow::stopSlideshow()
{
    qDebug() << "stahping slideshow";
    slide_timer->stop();
    //this->showNormal();
}

void MainWindow::restartSlideshow(int na)
{
    qDebug() << "restarting slideshow";
    na = 0; //-Wunused-parameter
    stopSlideshow();
    startSlideshow();
}

void MainWindow::clearItem()
{
    qDebug() << "clearing item";
    current_manager->clear();
    list_index = 0;
    this->setWindowTitle("<None>");
    status_bar_text->setText("<Folder empty>");
    status_bar_speed->setText("");
}

// Load the file that is marked as the current file
void MainWindow::loadItem()
{
    qDebug() << "Loading Item at " << list_index;
    QString file = folder + "/" + list.at(list_index);
    QFileInfo fileInfo = QFileInfo(file);
    this->setWindowTitle(fileInfo.fileName());
    status_bar_text->setText(fileInfo.fileName());

    qDebug() << "Loading File " << file;

    goto_next_slide = false;
    if(image_manager->hasExtension(fileInfo.suffix()))
        current_manager = image_manager;
    else if(video_manager->hasExtension(fileInfo.suffix()))
        current_manager = video_manager;
    else {
        clearItem();
        return;
    }
    current_manager->load(file);
}

void MainWindow::volumeChange(int change)
{
    //TODO: volume_dial->pageStep() ???
    qDebug() << "Volume = " << change;
    //if(volume_dial->value()!=change)
        //volume_dial->setValue(change); //TODO: This is supposed to sync up key shortcuts & the dial

    current_manager->setVolume(change);
}

void MainWindow::resizeEvent(QResizeEvent * qre)
{
    qDebug() << "resizing";
    if(current_manager!= NULL)
        current_manager->resize(qre);

    qre->accept();
}

void MainWindow::dropEvent(QDropEvent *de)
{
    qDebug() << "dropping";
    if(de->mimeData()->hasUrls())
    {
        QString path = de->mimeData()->urls().first().toString().remove(0, QString("file:///").length());
        QFileInfo pathInfo = QFileInfo(path);
        qDebug() << "dropped: " << path;
        if(pathInfo.isFile()) {
            if(image_manager->hasExtension(pathInfo.suffix()))
                image_manager->checkExtension(pathInfo.suffix());
            else if(video_manager->hasExtension(pathInfo.suffix()))
                video_manager->checkExtension(pathInfo.suffix());
            else {
                qDebug() << "ERROR Invalid filetype: " << pathInfo.suffix();
                return;
            }
        }
        if(pathInfo.isDir())
            loadFolder(path);
        else
            loadFolder(pathInfo.dir().absolutePath(), pathInfo.fileName());
    }
}
<commit_msg>Fixed browse dialogs clearing the image if the user cancels<commit_after>#include "main_window.h"
#include "ui_mainwindow.h"
#include "quca.hpp"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
    //, ui(new Ui::MainWindow)
{
    setWindowTitle("Quite");
    slide_timer = new QTimer();

    qDebug() << "Main Window Started";
    setGeometry(QRect(0, 0, WIDTH, HEIGHT));
    QSizePolicy pol(QSizePolicy::Preferred, QSizePolicy::Preferred);
    pol.setHorizontalStretch(0);
    pol.setVerticalStretch(0);
    setSizePolicy(pol);
    layout()->setMargin(11);
    layout()->setSpacing(6);
    qDebug() << "X";

    // Setup the managers
    image_manager = new ImageManager(this);
    video_manager = new VideoManager(this);

    // Setup the Menu
    //this->menuBar()->setGeometry(0, 0, WIDTH, 22);
    QMenu* browse_menu = menuBar()->addMenu(tr("&Browse"));
    QAction *file = browse_menu->addAction(tr("F&ile")),
             *folder = browse_menu->addAction(tr("F&older"));
    connect(file, SIGNAL(triggered()), this, SLOT(browseForFile()));
    connect(folder, SIGNAL(triggered()), this, SLOT(browseForFolder()));
    //*/

    // Setup the StatusBar
    for(QCheckBox* check : image_manager->getChecks()) {
        QMainWindow::connect(check, SIGNAL(clicked()), this, SLOT(reloadFolder()));
        statusBar()->addWidget(check);
        status_bar_widgets.append(check);
    }
    for(QCheckBox* check : video_manager->getChecks()) {
        QMainWindow::connect(check, SIGNAL(clicked()), this, SLOT(reloadFolder()));
        statusBar()->addWidget(check);
        status_bar_widgets.append(check);
    }

    status_bar_speed = new QLabel();
    statusBar()->addWidget(status_bar_speed);
    status_bar_widgets.append(status_bar_speed);

    slideshow_button = new QPushButton(tr("Slide"));
    slideshow_button->setFocusPolicy(Qt::NoFocus);
    statusBar()->addWidget(slideshow_button);
    status_bar_widgets.append(slideshow_button);

    slideshow_time = new QSpinBox();
    slideshow_time->setValue(3);
    slideshow_time->setSuffix("s");
    slideshow_time->setRange(1, 60);
    slideshow_time->setFocusPolicy(Qt::NoFocus);
    statusBar()->addWidget(slideshow_time);
    status_bar_widgets.append(slideshow_time);

    random_order = new QCheckBox(tr("Random"));
    statusBar()->addWidget(random_order);
    status_bar_widgets.append(random_order);

    volume_dial = new QDial();
    volume_dial->setFocusPolicy(Qt::NoFocus);
    volume_dial->setMinimum(0);
    volume_dial->setMaximum(100);
    volume_dial->setNotchesVisible(true);
    volume_dial->setSingleStep(5);
    volume_dial->setBaseSize(20, 20);
    volume_dial->setMaximumSize(QSize(30,30));
    volume_dial->setWrapping(false); //WTF does this do?
    statusBar()->addWidget(volume_dial);
    status_bar_widgets.append(volume_dial);

    status_bar_text = new QLabel();
    status_bar_text->setAlignment(Qt::AlignRight);
    statusBar()->addWidget(status_bar_text);
    status_bar_widgets.append(status_bar_text);

    connect(random_order, SIGNAL(clicked()), this, SLOT(reloadFolder()));
    connect(slideshow_button, SIGNAL(clicked()), this, SLOT(slideshowButton()));
    connect(slide_timer, SIGNAL(timeout()), this, SLOT(nextItemWhenConvenient()));
    connect(slideshow_time, SIGNAL(valueChanged(int)), this, SLOT(restartSlideshow(int)));
    connect(volume_dial, SIGNAL(valueChanged(int)), this, SLOT(volumeChange(int)));

    for(QWidget* widget : status_bar_widgets)
        widget->setDisabled(true);

    qDebug() << "mainWindow created";
}

// Destructor
MainWindow::~MainWindow()
{
    qDebug() << "Destroying mainWindow";

    delete slide_timer;

    qDebug() << "Destroyed mainWindow";
}

// Start or stop the slideshow
void MainWindow::slideshowButton()
{
    qDebug() << "Slideshow Button";
    if(slide_timer->isActive()) {
        stopSlideshow();
        slideshow_button->setText("Slide");
    } else {
        startSlideshow();
        slideshow_button->setText("Stop");
    }
}

// Call 'loadFolder' again on the current folder (& current file)
void MainWindow::reloadFolder()
{
    qDebug() << "reloading folder";
    if(list_index>=0 && list_index<list.size())
        loadFolder(this->folder, list.at(list_index));
    else
        loadFolder(this->folder);
}

// Read a folder's files
void MainWindow::loadFolder(QString folder, QString file)
{
    qDebug() << "Loading Folder " << folder;
    QStringList filetypes_want;
    image_manager->addCheckedFiletypesTo(filetypes_want);
    video_manager->addCheckedFiletypesTo(filetypes_want);

    // If there are no checked filetypes
    if(filetypes_want.size()==0) {
        clearItem(); return; }

    // Check to see if the file we want is the same as is already loaded to avoid reloading it.
    bool sameFile =
            //Same folder
            this->folder==folder &&
            // Same file
            (
                list_index>0 &&
                list.length()>list_index &&
                file==list.at(list_index)
            ) &&
            // Extension checkbox for this file is checked
            filetypes_want.contains(QString("*.").append(QFileInfo(file).suffix()));

    // Set the folder & load the files
    this->folder = folder;
    list = QDir(folder).entryList(filetypes_want);

    // If there are no files
    if(list.length()==0) {
        clearItem(); return; }

    qDebug() << "Files: " << list.size();

    // Sort (or anti-sort) the list
    if(random_order->isChecked())
        std::random_shuffle(list.begin(), list.end());
    else
        QUnicodeCollationAlgorithm::collatorKeySort(list);

    // Determine if this was a reload, in which case we should not reload the current item
    if(sameFile) {
        qDebug() << "Reloading same file, so not re-starting it";
        return;
    }

    // Set the current file's index in the list
    if(file=="" || list.indexOf(file,0)<0)
        list_index = 0;
    else
        list_index = list.indexOf(file,0);

    for(QWidget* widget : status_bar_widgets)
        widget->setDisabled(false);

    loadItem();
}

void MainWindow::browseForFile()
{
    QString file = QFileDialog::getOpenFileName(this); //TODO filetype filtering
    if(file.length()==0)
        return;
    QFileInfo fileinfo(file);
    if(fileinfo.isDir())
        loadFolder(fileinfo.filePath());
    else
        loadFolder(fileinfo.absoluteDir().absolutePath(), fileinfo.fileName());
}

void MainWindow::browseForFolder()
{
    QString newFolder = QFileDialog::getExistingDirectory(this);
    if(newFolder.length()>0)
        loadFolder(newFolder);
}

void MainWindow::wheelEvent(QWheelEvent *event)
{
    qDebug() << "WheelEvent";
    if (event->modifiers().testFlag(Qt::ControlModifier)) {
        //Zoom
    } else if (event->modifiers().testFlag(Qt::AltModifier)) {
        if(event->delta()>0)
            current_manager->faster();
        else
            current_manager->slower();
    } else {
        if(event->delta()<0)
            nextItem();
        else
            prevItem();
    }

}

void MainWindow::mousePressEvent(QMouseEvent * me)
{
    return;
    if(me->button()==Qt::LeftButton)
        nextItem();
    else if(me->button()==Qt::RightButton)
        prevItem();
}

void MainWindow::keyPressEvent(QKeyEvent * e)
{
    e->accept();
    switch (e->key()) {
        case Qt::Key_Right:
            nextItem();
            break;
        case Qt::Key_Left:
            prevItem();
            break;
        case Qt::Key_Plus:
            current_manager->faster();
            break;
        case Qt::Key_Minus:
            current_manager->slower();
            break;
        case Qt::Key_0:
            setSpeed();
            break;
        case Qt::Key_AsciiTilde:
            startSlideshow();
            return;
        case Qt::Key_Escape:
            stopSlideshow();
            return;
        case Qt::Key_Space:
            slideshowButton();
            return;
        case Qt::Key_P:
            if(current_manager->togglePause())
                stopSlideshow();
            else if(slide_timer->isActive())
                restartSlideshow();
            return;
        default:
            return;
    }
    if(slide_timer->isActive())
        restartSlideshow();
}

void MainWindow::nextItem()
{
    qDebug() << "nextItem";
    ++list_index;
    if(list_index==list.size())
        list_index = 0;
    loadItem();
}

void MainWindow::prevItem()
{
    qDebug() << "prevItem";
    if(list_index==0)
        list_index = list.size();
    --list_index;
    loadItem();
}

void MainWindow::setSpeed(double d)
{
    qDebug() << "setSpeed " << d;
    current_manager->setSpeed(d);
    status_bar_speed->setText(QString("%1x").arg(d/100.0));
}

void MainWindow::startSlideshow()
{
    qDebug() << "starting slideshow";
    slide_timer->start(slideshow_time->value() * 1000);
    //this->showFullScreen();
}

void MainWindow::stopSlideshow()
{
    qDebug() << "stahping slideshow";
    slide_timer->stop();
    //this->showNormal();
}

void MainWindow::restartSlideshow(int na)
{
    qDebug() << "restarting slideshow";
    na = 0; //-Wunused-parameter
    stopSlideshow();
    startSlideshow();
}

void MainWindow::clearItem()
{
    qDebug() << "clearing item";
    current_manager->clear();
    list_index = 0;
    this->setWindowTitle("<None>");
    status_bar_text->setText("<Folder empty>");
    status_bar_speed->setText("");
}

// Load the file that is marked as the current file
void MainWindow::loadItem()
{
    qDebug() << "Loading Item at " << list_index;
    QString file = folder + "/" + list.at(list_index);
    QFileInfo fileInfo = QFileInfo(file);
    this->setWindowTitle(fileInfo.fileName());
    status_bar_text->setText(fileInfo.fileName());

    qDebug() << "Loading File " << file;

    goto_next_slide = false;
    if(image_manager->hasExtension(fileInfo.suffix()))
        current_manager = image_manager;
    else if(video_manager->hasExtension(fileInfo.suffix()))
        current_manager = video_manager;
    else {
        clearItem();
        return;
    }
    current_manager->load(file);
}

void MainWindow::volumeChange(int change)
{
    //TODO: volume_dial->pageStep() ???
    qDebug() << "Volume = " << change;
    //if(volume_dial->value()!=change)
        //volume_dial->setValue(change); //TODO: This is supposed to sync up key shortcuts & the dial

    current_manager->setVolume(change);
}

void MainWindow::resizeEvent(QResizeEvent * qre)
{
    qDebug() << "resizing";
    if(current_manager!= NULL)
        current_manager->resize(qre);

    qre->accept();
}

void MainWindow::dropEvent(QDropEvent *de)
{
    qDebug() << "dropping";
    if(de->mimeData()->hasUrls())
    {
        QString path = de->mimeData()->urls().first().toString().remove(0, QString("file:///").length());
        QFileInfo pathInfo = QFileInfo(path);
        qDebug() << "dropped: " << path;
        if(pathInfo.isFile()) {
            if(image_manager->hasExtension(pathInfo.suffix()))
                image_manager->checkExtension(pathInfo.suffix());
            else if(video_manager->hasExtension(pathInfo.suffix()))
                video_manager->checkExtension(pathInfo.suffix());
            else {
                qDebug() << "ERROR Invalid filetype: " << pathInfo.suffix();
                return;
            }
        }
        if(pathInfo.isDir())
            loadFolder(path);
        else
            loadFolder(pathInfo.dir().absolutePath(), pathInfo.fileName());
    }
}
<|endoftext|>