<commit_before>/***************************************************************************
                          irkick.cpp  -  Implementation of the main window
                             -------------------
    copyright            : (C) 2002 by Gav Wood
    email                : gav@indigoarchive.net
***************************************************************************/

// This program is free software.

#include <qwidget.h>
#include <qdialog.h>
#include <qtooltip.h>
#include <qregexp.h>
#include <qtimer.h>
#include <qevent.h>

#include <kdeversion.h>
#include <kapplication.h>
#include <kaction.h>
#if !(KDE_VERSION_MINOR<=1 && KDE_VERSION_RELEASE<=5)
#include <kactioncollection.h>
#endif
#include <ksimpleconfig.h>
#include <ksystemtray.h>
#include <kiconloader.h>
#include <kpassivepopup.h>
#include <kmessagebox.h>
#include <kpopupmenu.h>
#include <kdebug.h>
#include <klocale.h>
#include <kaboutdialog.h>
#include <kaboutkde.h>
#include <kwinmodule.h>
#include <kwin.h>
#include <khelpmenu.h>
#include <kglobal.h>

#include <dcopclient.h>
#include <dcopref.h>

#include "profileserver.h"
#include "irkick.h"

void IRKTrayIcon::mousePressEvent(QMouseEvent *e)
{
	KSystemTray::mousePressEvent(new QMouseEvent(QEvent::MouseButtonPress, e->pos(), e->globalPos(), e->button() == LeftButton ? RightButton : e->button(), e->state()));
}

IRKick::IRKick(const QCString &obj) : QObject(), DCOPObject(obj), npApp(QString::null)
{
	theClient = new KLircClient();

	theTrayIcon = new IRKTrayIcon();
	if(theClient->isConnected())
	{	theTrayIcon->setPixmap(SmallIcon("irkick"));
		QToolTip::add(theTrayIcon, i18n("KDE Lirc Server: Ready."));
	}
	else
	{	theTrayIcon->setPixmap(SmallIcon("irkickoff"));
		QToolTip::add(theTrayIcon, i18n("KDE Lirc Server: No infra-red remote controls found."));
		QTimer::singleShot(10000, this, SLOT(checkLirc()));
	}
	theFlashOff = new QTimer(theTrayIcon);
	connect(theFlashOff, SIGNAL(timeout()), SLOT(flashOff()));

	theResetCount = 0;
	slotReloadConfiguration();
	connect(theClient, SIGNAL(connectionClosed()), this, SLOT(slotClosed()));
	connect(theClient, SIGNAL(remotesRead()), this, SLOT(resetModes()));
	connect(theClient, SIGNAL(commandReceived(const QString &, const QString &, int)), this, SLOT(gotMessage(const QString &, const QString &, int)));

	theTrayIcon->contextMenu()->changeTitle(0, "IRKick");
	theTrayIcon->contextMenu()->insertItem(SmallIcon( "configure" ), i18n("&Configure..."), this, SLOT(slotConfigure()));
	theTrayIcon->contextMenu()->insertSeparator();
	theTrayIcon->contextMenu()->insertItem(SmallIcon( "help" ), i18n("&Help"), (new KHelpMenu(theTrayIcon, KGlobal::instance()->aboutData()))->menu());
	theTrayIcon->actionCollection()->action("file_quit")->disconnect(SIGNAL(activated()));
	connect(theTrayIcon->actionCollection()->action("file_quit"), SIGNAL(activated()), SLOT(doQuit()));

	theTrayIcon->show();
}

IRKick::~IRKick()
{
	delete theTrayIcon;
	for(QMap<QString,IRKTrayIcon *>::iterator i = currentModeIcons.begin(); i != currentModeIcons.end(); i++)
		if(*i) delete *i;
}

void IRKick::slotClosed()
{
	theTrayIcon->setPixmap(SmallIcon("irkickoff"));
	KPassivePopup::message("IRKick", i18n("The infrared system has severed its connection. Remote controls are no longer available."), SmallIcon("irkick"), theTrayIcon);
	QTimer::singleShot(1000, this, SLOT(checkLirc()));
}

void IRKick::checkLirc()
{
	if(!theClient->isConnected())
		if(theClient->connectToLirc())
		{	KPassivePopup::message("IRKick", i18n("A connection to the infrared system has been made. Remote controls may now be available."), SmallIcon("irkick"), theTrayIcon);
			theTrayIcon->setPixmap(SmallIcon("irkick"));
		}
		else
			QTimer::singleShot(10000, this, SLOT(checkLirc()));
}

void IRKick::flashOff()
{
	theTrayIcon->setPixmap(SmallIcon("irkick"));
}

void IRKick::doQuit()
{
	KSimpleConfig theConfig("irkickrc");
	theConfig.setGroup("General");
	switch(KMessageBox::questionYesNoCancel(0, i18n("Should the Infrared Remote Control server start automatically when you begin KDE?"), i18n("Automatically Start?")))
	{	case KMessageBox::No: theConfig.writeEntry("AutoStart", false); break;
		case KMessageBox::Yes: theConfig.writeEntry("AutoStart", true); break;
		case KMessageBox::Cancel: return;
	}
	KApplication::kApplication()->quit();
}

void IRKick::resetModes()
{
	if(theResetCount > 1)
		KPassivePopup::message("IRKick", i18n("Resetting all modes."), SmallIcon("irkick"), theTrayIcon);
	if(!theResetCount)
		allModes.generateNulls(theClient->remotes());

	QStringList remotes = theClient->remotes();
	for(QStringList::iterator i = remotes.begin(); i != remotes.end(); i++)
	{	currentModes[*i] = allModes.getDefault(*i).name();
		if(theResetCount && currentModeIcons[*i]) delete currentModeIcons[*i];
		currentModeIcons[*i] = 0;
	}
	updateModeIcons();
	theResetCount++;
}

void IRKick::slotReloadConfiguration()
{
	// load configuration from config file
	KSimpleConfig theConfig("irkickrc");
	allActions.loadFromConfig(theConfig);
	allModes.loadFromConfig(theConfig);
	if(currentModes.count() && theResetCount)
		resetModes();
}

void IRKick::slotConfigure()
{
	KApplication::startServiceByDesktopName("kcmlirc");
}

void IRKick::updateModeIcons()
{
	for(QMap<QString,QString>::iterator i = currentModes.begin(); i != currentModes.end(); i++)
	{	Mode mode = allModes.getMode(i.key(), i.data());
		if(mode.iconFile() == QString::null || mode.iconFile() == "")
		{	if(currentModeIcons[i.key()])
			{	delete currentModeIcons[i.key()];
				currentModeIcons[i.key()] = 0;
			}
		}
		else
		{	if(!currentModeIcons[i.key()])
			{	currentModeIcons[i.key()] = new IRKTrayIcon();
				currentModeIcons[i.key()]->show();
				currentModeIcons[i.key()]->contextMenu()->changeTitle(0, mode.remoteName());
				currentModeIcons[i.key()]->actionCollection()->action("file_quit")->setEnabled(false);
			}
			currentModeIcons[i.key()]->setPixmap(KIconLoader().loadIcon(mode.iconFile(), KIcon::Panel));
			QToolTip::add(currentModeIcons[i.key()], mode.remoteName() + ": " + mode.name() + "");
		}
	}
}

bool IRKick::getPrograms(const IRAction &action, QStringList &programs)
{
	DCOPClient *theDC = KApplication::dcopClient();
	programs.clear();

	if(action.unique())
	{	if(theDC->isApplicationRegistered(action.program().utf8()))
			programs += action.program();
	}
	else
	{
		QRegExp r = QRegExp("^" + action.program() + "-(\\d+)$");
		// find all instances...
		QCStringList buf = theDC->registeredApplications();
		for(QCStringList::iterator i = buf.begin(); i != buf.end(); i++)
		{
			QString program = QString::fromUtf8(*i);
			if(program.contains(r))
				programs += program;
		}
		if(programs.size() > 1 && action.ifMulti() == IM_DONTSEND)
			return false;
		else if(programs.size() > 1 && action.ifMulti() == IM_SENDTOTOP)
		{	QValueList<WId> s = KWinModule().stackingOrder();
			// go through all the (ordered) window pids
			for(QValueList<WId>::iterator i = s.fromLast(); i != s.end(); i--)
			{	int p = KWin::info(*i).pid;
				QString id = action.program() + "-" + QString().setNum(p);
				if(programs.contains(id))
				{	programs.clear();
					programs += id;
					break;
				}
			}
			while(programs.size() > 1) programs.remove(programs.begin());
		}
		else if(programs.size() > 1 && action.ifMulti() == IM_SENDTOBOTTOM)
		{	QValueList<WId> s = KWinModule().stackingOrder();
			// go through all the (ordered) window pids
			for(QValueList<WId>::iterator i = s.begin(); i != s.end(); i++)
			{	int p = KWin::info(*i).pid;
				QString id = action.program() + "-" + QString().setNum(p);
				if(programs.contains(id))
				{	programs.clear();
					programs += id;
					break;
				}
			}
			while(programs.size() > 1) programs.remove(programs.begin());
		}
	}
	return true;
}

void IRKick::executeAction(const IRAction &action)
{
	DCOPClient *theDC = KApplication::dcopClient();
	QStringList programs;

	if(!getPrograms(action, programs)) return;

	// if programs.size()==0 here, then the app is definately not running.
	if(action.autoStart() && !programs.size())
	{	QString sname = ProfileServer::profileServer()->getServiceName(action.program());
		if(sname != QString::null)
		{
			KPassivePopup::message("IRKick", i18n("Starting %1...").arg(action.application()), SmallIcon("irkick"), theTrayIcon);
			KApplication::startServiceByDesktopName(sname);
		}
	}
	if(action.isJustStart()) return;

	if(!getPrograms(action, programs)) return;

	for(QStringList::iterator i = programs.begin(); i != programs.end(); i++)
	{	const QString &program = *i;
		if(theDC->isApplicationRegistered(program.utf8()))
		{	QByteArray data; QDataStream arg(data, IO_WriteOnly);
			kdDebug() << "Sending data (" << program << ", " << action.object() << ", " << action.method().prototypeNR() << endl;
			for(Arguments::const_iterator j = action.arguments().begin(); j != action.arguments().end(); j++)
			{	kdDebug() << "Got argument..." << endl;
				switch((*j).type())
				{	case QVariant::Int: arg << (*j).toInt(); break;
					case QVariant::CString: arg << (*j).toCString(); break;
					case QVariant::StringList: arg << (*j).toStringList(); break;
					case QVariant::UInt: arg << (*j).toUInt(); break;
					case QVariant::Bool: arg << (*j).toBool(); break;
					case QVariant::Double: arg << (*j).toDouble(); break;
					default: arg << (*j).toString(); break;
				}
			}
			theDC->send(program.utf8(), action.object().utf8(), action.method().prototypeNR().utf8(), data);
		}
	}
}

void IRKick::gotMessage(const QString &theRemote, const QString &theButton, int theRepeatCounter)
{
	kdDebug() << "Got message: " << theRemote << ": " << theButton << " (" << theRepeatCounter << ")" << endl;
	theTrayIcon->setPixmap(SmallIcon("irkickflash"));
	theFlashOff->start(200, true);
	if(npApp != QString::null)
	{
		QString theApp = npApp;
		npApp = QString::null;
		// send notifier by DCOP to npApp/npModule/npMethod(theRemote, theButton);
		QByteArray data; QDataStream arg(data, IO_WriteOnly);
		arg << theRemote << theButton;
		KApplication::dcopClient()->send(theApp.utf8(), npModule.utf8(), npMethod.utf8(), data);
	}
	else
	{
		if(currentModes[theRemote].isNull()) currentModes[theRemote] = "";
		IRAItList l = allActions.findByModeButton(Mode(theRemote, currentModes[theRemote]), theButton);
		if(currentModes[theRemote] != "")
			l += allActions.findByModeButton(Mode(theRemote, ""), theButton);
		bool doBefore = true, doAfter = false;
		for(IRAItList::const_iterator i = l.begin(); i != l.end(); i++)
			if((**i).isModeChange() && !theRepeatCounter)
			{	// mode switch
				currentModes[theRemote] = (**i).modeChange();
				Mode mode = allModes.getMode(theRemote, (**i).modeChange());
				updateModeIcons();
				doBefore = (**i).doBefore();
				doAfter = (**i).doAfter();
				break;
			}

		for(int after = 0; after < 2; after++)
		{	if(doBefore && !after || doAfter && after)
				for(IRAItList::const_iterator i = l.begin(); i != l.end(); i++)
					if(!(**i).isModeChange() && ((**i).repeat() || !theRepeatCounter))
					{	executeAction(**i);
					}
			if(!after && doAfter)
			{	l = allActions.findByModeButton(Mode(theRemote, currentModes[theRemote]), theButton);
				if(currentModes[theRemote] != "")
					l += allActions.findByModeButton(Mode(theRemote, ""), theButton);
			}
		}
	}
}

void IRKick::stealNextPress(QString app, QString module, QString method)
{
	npApp = app;
	npModule = module;
	npMethod = method;
}

void IRKick::dontStealNextPress()
{
	npApp = QString::null;
}

#include "irkick.moc"
<commit_msg>Make "IRKick" the default DCOPObject<commit_after>/***************************************************************************
                          irkick.cpp  -  Implementation of the main window
                             -------------------
    copyright            : (C) 2002 by Gav Wood
    email                : gav@indigoarchive.net
***************************************************************************/

// This program is free software.

#include <qwidget.h>
#include <qdialog.h>
#include <qtooltip.h>
#include <qregexp.h>
#include <qtimer.h>
#include <qevent.h>

#include <kdeversion.h>
#include <kapplication.h>
#include <kaction.h>
#if !(KDE_VERSION_MINOR<=1 && KDE_VERSION_RELEASE<=5)
#include <kactioncollection.h>
#endif
#include <ksimpleconfig.h>
#include <ksystemtray.h>
#include <kiconloader.h>
#include <kpassivepopup.h>
#include <kmessagebox.h>
#include <kpopupmenu.h>
#include <kdebug.h>
#include <klocale.h>
#include <kaboutdialog.h>
#include <kaboutkde.h>
#include <kwinmodule.h>
#include <kwin.h>
#include <khelpmenu.h>
#include <kglobal.h>

#include <dcopclient.h>
#include <dcopref.h>

#include "profileserver.h"
#include "irkick.h"

void IRKTrayIcon::mousePressEvent(QMouseEvent *e)
{
	KSystemTray::mousePressEvent(new QMouseEvent(QEvent::MouseButtonPress, e->pos(), e->globalPos(), e->button() == LeftButton ? RightButton : e->button(), e->state()));
}

IRKick::IRKick(const QCString &obj) : QObject(), DCOPObject(obj), npApp(QString::null)
{
    kapp->dcopClient()->setDefaultObject(obj);
	theClient = new KLircClient();

	theTrayIcon = new IRKTrayIcon();
	if(theClient->isConnected())
	{	theTrayIcon->setPixmap(SmallIcon("irkick"));
		QToolTip::add(theTrayIcon, i18n("KDE Lirc Server: Ready."));
	}
	else
	{	theTrayIcon->setPixmap(SmallIcon("irkickoff"));
		QToolTip::add(theTrayIcon, i18n("KDE Lirc Server: No infra-red remote controls found."));
		QTimer::singleShot(10000, this, SLOT(checkLirc()));
	}
	theFlashOff = new QTimer(theTrayIcon);
	connect(theFlashOff, SIGNAL(timeout()), SLOT(flashOff()));

	theResetCount = 0;
	slotReloadConfiguration();
	connect(theClient, SIGNAL(connectionClosed()), this, SLOT(slotClosed()));
	connect(theClient, SIGNAL(remotesRead()), this, SLOT(resetModes()));
	connect(theClient, SIGNAL(commandReceived(const QString &, const QString &, int)), this, SLOT(gotMessage(const QString &, const QString &, int)));

	theTrayIcon->contextMenu()->changeTitle(0, "IRKick");
	theTrayIcon->contextMenu()->insertItem(SmallIcon( "configure" ), i18n("&Configure..."), this, SLOT(slotConfigure()));
	theTrayIcon->contextMenu()->insertSeparator();
	theTrayIcon->contextMenu()->insertItem(SmallIcon( "help" ), i18n("&Help"), (new KHelpMenu(theTrayIcon, KGlobal::instance()->aboutData()))->menu());
	theTrayIcon->actionCollection()->action("file_quit")->disconnect(SIGNAL(activated()));
	connect(theTrayIcon->actionCollection()->action("file_quit"), SIGNAL(activated()), SLOT(doQuit()));

	theTrayIcon->show();
}

IRKick::~IRKick()
{
	delete theTrayIcon;
	for(QMap<QString,IRKTrayIcon *>::iterator i = currentModeIcons.begin(); i != currentModeIcons.end(); i++)
		if(*i) delete *i;
}

void IRKick::slotClosed()
{
	theTrayIcon->setPixmap(SmallIcon("irkickoff"));
	KPassivePopup::message("IRKick", i18n("The infrared system has severed its connection. Remote controls are no longer available."), SmallIcon("irkick"), theTrayIcon);
	QTimer::singleShot(1000, this, SLOT(checkLirc()));
}

void IRKick::checkLirc()
{
	if(!theClient->isConnected())
		if(theClient->connectToLirc())
		{	KPassivePopup::message("IRKick", i18n("A connection to the infrared system has been made. Remote controls may now be available."), SmallIcon("irkick"), theTrayIcon);
			theTrayIcon->setPixmap(SmallIcon("irkick"));
		}
		else
			QTimer::singleShot(10000, this, SLOT(checkLirc()));
}

void IRKick::flashOff()
{
	theTrayIcon->setPixmap(SmallIcon("irkick"));
}

void IRKick::doQuit()
{
	KSimpleConfig theConfig("irkickrc");
	theConfig.setGroup("General");
	switch(KMessageBox::questionYesNoCancel(0, i18n("Should the Infrared Remote Control server start automatically when you begin KDE?"), i18n("Automatically Start?")))
	{	case KMessageBox::No: theConfig.writeEntry("AutoStart", false); break;
		case KMessageBox::Yes: theConfig.writeEntry("AutoStart", true); break;
		case KMessageBox::Cancel: return;
	}
	KApplication::kApplication()->quit();
}

void IRKick::resetModes()
{
	if(theResetCount > 1)
		KPassivePopup::message("IRKick", i18n("Resetting all modes."), SmallIcon("irkick"), theTrayIcon);
	if(!theResetCount)
		allModes.generateNulls(theClient->remotes());

	QStringList remotes = theClient->remotes();
	for(QStringList::iterator i = remotes.begin(); i != remotes.end(); i++)
	{	currentModes[*i] = allModes.getDefault(*i).name();
		if(theResetCount && currentModeIcons[*i]) delete currentModeIcons[*i];
		currentModeIcons[*i] = 0;
	}
	updateModeIcons();
	theResetCount++;
}

void IRKick::slotReloadConfiguration()
{
	// load configuration from config file
	KSimpleConfig theConfig("irkickrc");
	allActions.loadFromConfig(theConfig);
	allModes.loadFromConfig(theConfig);
	if(currentModes.count() && theResetCount)
		resetModes();
}

void IRKick::slotConfigure()
{
	KApplication::startServiceByDesktopName("kcmlirc");
}

void IRKick::updateModeIcons()
{
	for(QMap<QString,QString>::iterator i = currentModes.begin(); i != currentModes.end(); i++)
	{	Mode mode = allModes.getMode(i.key(), i.data());
		if(mode.iconFile() == QString::null || mode.iconFile() == "")
		{	if(currentModeIcons[i.key()])
			{	delete currentModeIcons[i.key()];
				currentModeIcons[i.key()] = 0;
			}
		}
		else
		{	if(!currentModeIcons[i.key()])
			{	currentModeIcons[i.key()] = new IRKTrayIcon();
				currentModeIcons[i.key()]->show();
				currentModeIcons[i.key()]->contextMenu()->changeTitle(0, mode.remoteName());
				currentModeIcons[i.key()]->actionCollection()->action("file_quit")->setEnabled(false);
			}
			currentModeIcons[i.key()]->setPixmap(KIconLoader().loadIcon(mode.iconFile(), KIcon::Panel));
			QToolTip::add(currentModeIcons[i.key()], mode.remoteName() + ": " + mode.name() + "");
		}
	}
}

bool IRKick::getPrograms(const IRAction &action, QStringList &programs)
{
	DCOPClient *theDC = KApplication::dcopClient();
	programs.clear();

	if(action.unique())
	{	if(theDC->isApplicationRegistered(action.program().utf8()))
			programs += action.program();
	}
	else
	{
		QRegExp r = QRegExp("^" + action.program() + "-(\\d+)$");
		// find all instances...
		QCStringList buf = theDC->registeredApplications();
		for(QCStringList::iterator i = buf.begin(); i != buf.end(); i++)
		{
			QString program = QString::fromUtf8(*i);
			if(program.contains(r))
				programs += program;
		}
		if(programs.size() > 1 && action.ifMulti() == IM_DONTSEND)
			return false;
		else if(programs.size() > 1 && action.ifMulti() == IM_SENDTOTOP)
		{	QValueList<WId> s = KWinModule().stackingOrder();
			// go through all the (ordered) window pids
			for(QValueList<WId>::iterator i = s.fromLast(); i != s.end(); i--)
			{	int p = KWin::info(*i).pid;
				QString id = action.program() + "-" + QString().setNum(p);
				if(programs.contains(id))
				{	programs.clear();
					programs += id;
					break;
				}
			}
			while(programs.size() > 1) programs.remove(programs.begin());
		}
		else if(programs.size() > 1 && action.ifMulti() == IM_SENDTOBOTTOM)
		{	QValueList<WId> s = KWinModule().stackingOrder();
			// go through all the (ordered) window pids
			for(QValueList<WId>::iterator i = s.begin(); i != s.end(); i++)
			{	int p = KWin::info(*i).pid;
				QString id = action.program() + "-" + QString().setNum(p);
				if(programs.contains(id))
				{	programs.clear();
					programs += id;
					break;
				}
			}
			while(programs.size() > 1) programs.remove(programs.begin());
		}
	}
	return true;
}

void IRKick::executeAction(const IRAction &action)
{
	DCOPClient *theDC = KApplication::dcopClient();
	QStringList programs;

	if(!getPrograms(action, programs)) return;

	// if programs.size()==0 here, then the app is definately not running.
	if(action.autoStart() && !programs.size())
	{	QString sname = ProfileServer::profileServer()->getServiceName(action.program());
		if(sname != QString::null)
		{
			KPassivePopup::message("IRKick", i18n("Starting %1...").arg(action.application()), SmallIcon("irkick"), theTrayIcon);
			KApplication::startServiceByDesktopName(sname);
		}
	}
	if(action.isJustStart()) return;

	if(!getPrograms(action, programs)) return;

	for(QStringList::iterator i = programs.begin(); i != programs.end(); i++)
	{	const QString &program = *i;
		if(theDC->isApplicationRegistered(program.utf8()))
		{	QByteArray data; QDataStream arg(data, IO_WriteOnly);
			kdDebug() << "Sending data (" << program << ", " << action.object() << ", " << action.method().prototypeNR() << endl;
			for(Arguments::const_iterator j = action.arguments().begin(); j != action.arguments().end(); j++)
			{	kdDebug() << "Got argument..." << endl;
				switch((*j).type())
				{	case QVariant::Int: arg << (*j).toInt(); break;
					case QVariant::CString: arg << (*j).toCString(); break;
					case QVariant::StringList: arg << (*j).toStringList(); break;
					case QVariant::UInt: arg << (*j).toUInt(); break;
					case QVariant::Bool: arg << (*j).toBool(); break;
					case QVariant::Double: arg << (*j).toDouble(); break;
					default: arg << (*j).toString(); break;
				}
			}
			theDC->send(program.utf8(), action.object().utf8(), action.method().prototypeNR().utf8(), data);
		}
	}
}

void IRKick::gotMessage(const QString &theRemote, const QString &theButton, int theRepeatCounter)
{
	kdDebug() << "Got message: " << theRemote << ": " << theButton << " (" << theRepeatCounter << ")" << endl;
	theTrayIcon->setPixmap(SmallIcon("irkickflash"));
	theFlashOff->start(200, true);
	if(npApp != QString::null)
	{
		QString theApp = npApp;
		npApp = QString::null;
		// send notifier by DCOP to npApp/npModule/npMethod(theRemote, theButton);
		QByteArray data; QDataStream arg(data, IO_WriteOnly);
		arg << theRemote << theButton;
		KApplication::dcopClient()->send(theApp.utf8(), npModule.utf8(), npMethod.utf8(), data);
	}
	else
	{
		if(currentModes[theRemote].isNull()) currentModes[theRemote] = "";
		IRAItList l = allActions.findByModeButton(Mode(theRemote, currentModes[theRemote]), theButton);
		if(currentModes[theRemote] != "")
			l += allActions.findByModeButton(Mode(theRemote, ""), theButton);
		bool doBefore = true, doAfter = false;
		for(IRAItList::const_iterator i = l.begin(); i != l.end(); i++)
			if((**i).isModeChange() && !theRepeatCounter)
			{	// mode switch
				currentModes[theRemote] = (**i).modeChange();
				Mode mode = allModes.getMode(theRemote, (**i).modeChange());
				updateModeIcons();
				doBefore = (**i).doBefore();
				doAfter = (**i).doAfter();
				break;
			}

		for(int after = 0; after < 2; after++)
		{	if(doBefore && !after || doAfter && after)
				for(IRAItList::const_iterator i = l.begin(); i != l.end(); i++)
					if(!(**i).isModeChange() && ((**i).repeat() || !theRepeatCounter))
					{	executeAction(**i);
					}
			if(!after && doAfter)
			{	l = allActions.findByModeButton(Mode(theRemote, currentModes[theRemote]), theButton);
				if(currentModes[theRemote] != "")
					l += allActions.findByModeButton(Mode(theRemote, ""), theButton);
			}
		}
	}
}

void IRKick::stealNextPress(QString app, QString module, QString method)
{
	npApp = app;
	npModule = module;
	npMethod = method;
}

void IRKick::dontStealNextPress()
{
	npApp = QString::null;
}

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


<commit_before>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016-2021 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#ifndef LIBCOUCHBASE_CAPI_COLLECTION_QUALIFIER_HH
#define LIBCOUCHBASE_CAPI_COLLECTION_QUALIFIER_HH

#include <cstddef>
#include <cstdint>
#include <string>
#include <sstream>
#include <stdexcept>

namespace lcb
{
/**
 * @private
 */
struct collection_qualifier {
    collection_qualifier() = default;

    collection_qualifier(const char *scope_name, std::size_t scope_name_len, const char *collection_name,
                         std::size_t collection_name_len)
    {
        if (!is_valid_collection_element(scope_name, scope_name_len)) {
            throw std::invalid_argument("invalid scope name");
        }
        if (!is_valid_collection_element(collection_name, collection_name_len)) {
            throw std::invalid_argument("invalid collection name");
        }

        if (scope_name != nullptr && scope_name_len > 0) {
            scope_.assign(scope_name, scope_name_len);
        }
        if (collection_name != nullptr && collection_name_len > 0) {
            collection_.assign(collection_name, collection_name_len);
        }
        std::stringstream ss;
        ss << (scope_.empty() ? "_default" : scope_);
        ss << '.';
        ss << (collection_.empty() ? "_default" : collection_);
        spec_ = ss.str();
    }

    const std::string &scope() const
    {
        return scope_;
    }

    const std::string &collection() const
    {
        return collection_;
    }

    bool has_default_scope() const
    {
        return scope_.empty() || scope_ == "_default";
    }

    bool is_default_collection() const
    {
        return has_default_scope() && (collection_.empty() || collection_ == "_default");
    }

    bool is_resolved() const
    {
        return resolved_;
    }

    std::uint32_t collection_id() const
    {
        return resolved_collection_id_;
    }

    void collection_id(std::uint32_t id)
    {
        resolved_collection_id_ = id;
        resolved_ = true;
    }

    const std::string &spec() const
    {
        return spec_;
    }

  private:
    static bool is_valid_collection_char(char ch)
    {
        if (ch >= 'A' && ch <= 'Z') {
            return true;
        }
        if (ch >= 'a' && ch <= 'z') {
            return true;
        }
        if (ch >= '0' && ch <= '9') {
            return true;
        }
        switch (ch) {
            case '_':
            case '-':
            case '%':
                return true;
            default:
                return false;
        }
    }

    static bool is_valid_collection_element(const char *element, size_t element_len)
    {
        if (element_len == 0 || element == nullptr) {
            /* nullptr/0 for collection is mapped to default collection */
            return true;
        }
        if (element_len < 1 || element_len > 30) {
            return false;
        }
        for (size_t i = 0; i < element_len; ++i) {
            if (!is_valid_collection_char(element[i])) {
                return false;
            }
        }
        return true;
    }

    std::string scope_{"_default"};
    std::string collection_{"_default"};
    std::string spec_{};
    std::uint32_t resolved_collection_id_{0};
    bool resolved_{false};
};
} // namespace lcb

#endif // LIBCOUCHBASE_CAPI_COLLECTION_QUALIFIER_HH
<commit_msg>CCBC-1525: remove stringstream in collection_qualifier<commit_after>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016-2021 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#ifndef LIBCOUCHBASE_CAPI_COLLECTION_QUALIFIER_HH
#define LIBCOUCHBASE_CAPI_COLLECTION_QUALIFIER_HH

#include <cstddef>
#include <cstdint>
#include <string>
#include <stdexcept>

namespace lcb
{
/**
 * @private
 */
struct collection_qualifier {
    collection_qualifier() = default;

    collection_qualifier(const char *scope_name, std::size_t scope_name_len, const char *collection_name,
                         std::size_t collection_name_len)
    {
        if (!is_valid_collection_element(scope_name, scope_name_len)) {
            throw std::invalid_argument("invalid scope name");
        }
        if (!is_valid_collection_element(collection_name, collection_name_len)) {
            throw std::invalid_argument("invalid collection name");
        }

        if (scope_name != nullptr && scope_name_len > 0) {
            scope_.assign(scope_name, scope_name_len);
        }
        if (collection_name != nullptr && collection_name_len > 0) {
            collection_.assign(collection_name, collection_name_len);
        }

        spec_ = (scope_.empty() ? "_default" : scope_) +
                '.' +
                (collection_.empty() ? "_default" : collection_);
    }

    const std::string &scope() const
    {
        return scope_;
    }

    const std::string &collection() const
    {
        return collection_;
    }

    bool has_default_scope() const
    {
        return scope_.empty() || scope_ == "_default";
    }

    bool is_default_collection() const
    {
        return has_default_scope() && (collection_.empty() || collection_ == "_default");
    }

    bool is_resolved() const
    {
        return resolved_;
    }

    std::uint32_t collection_id() const
    {
        return resolved_collection_id_;
    }

    void collection_id(std::uint32_t id)
    {
        resolved_collection_id_ = id;
        resolved_ = true;
    }

    const std::string &spec() const
    {
        return spec_;
    }

  private:
    static bool is_valid_collection_char(char ch)
    {
        if (ch >= 'A' && ch <= 'Z') {
            return true;
        }
        if (ch >= 'a' && ch <= 'z') {
            return true;
        }
        if (ch >= '0' && ch <= '9') {
            return true;
        }
        switch (ch) {
            case '_':
            case '-':
            case '%':
                return true;
            default:
                return false;
        }
    }

    static bool is_valid_collection_element(const char *element, size_t element_len)
    {
        if (element_len == 0 || element == nullptr) {
            /* nullptr/0 for collection is mapped to default collection */
            return true;
        }
        if (element_len < 1 || element_len > 30) {
            return false;
        }
        for (size_t i = 0; i < element_len; ++i) {
            if (!is_valid_collection_char(element[i])) {
                return false;
            }
        }
        return true;
    }

    std::string scope_{"_default"};
    std::string collection_{"_default"};
    std::string spec_{};
    std::uint32_t resolved_collection_id_{0};
    bool resolved_{false};
};
} // namespace lcb

#endif // LIBCOUCHBASE_CAPI_COLLECTION_QUALIFIER_HH
<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_IO_TIKZ_HH__
#define ALEPH_TOPOLOGY_IO_TIKZ_HH__

#include <fstream>
#include <ostream>
#include <stdexcept>
#include <string>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class TikZ
  @brief Writes files as a TikZ picture

  This writer class uses coordinate information of a simplicial complex
  to represent its 1-skeleton, i.e. its vertices and edges. All data is
  stored as a picture for the TikZ LaTeX toolkit, resulting in a clean,
  modern output for publications.

  The output is configurable and permits the following adjustments:

    - point size
    - line width
*/

class TikZ
{
public:

  /** Writes the simplicial complex to a new file. */
  template <class SimplicialComplex, class Container> void operator()( const std::string& filename,
                                                                       const SimplicialComplex& K,
                                                                       const Container& container )
  {
    std::ofstream out( filename );
    if( !out )
      throw std::runtime_error( "Unable to open output file" );

    this->operator()( out, K, container );
  }

  /** Writes the simplicial complex to a new output stream. */
  template <class SimplicialComplex, class Container> void operator()( std::ostream& out,
                                                                       const SimplicialComplex& K,
                                                                       const Container& container )
  {
    out << "\\begin{tikzpicture}\n";

    // Render vertices as points ---------------------------------------

    out << "% 0-simplices\n";

    for( auto&& s : K )
    {
      if( s.dimension() != 0 )
        continue;

      auto u = s[0];         // vertex
      auto p = container[u]; // coordinate

      if( p.size() >= 2 )
        writePoint( out, u, p );
      else
        throw std::runtime_error( "Insufficient number of dimensions for storing coordinates" );
    }

    // Render edges as lines -------------------------------------------

    out << "% 1-simplices\n";

    for( auto&& s : K )
    {
      if( s.dimension() != 1 )
        continue;

      auto u = s[0];         // vertex
      auto v = s[1];         // vertex

      writeEdge(out, u, v);
    }

    out << "\\end{tikzpicture}\n";
  }

  bool showVertexLabels() const noexcept
  {
    return _showVertexLabels;
  }

  void showVertexLabels( bool value ) noexcept
  {
    _showVertexLabels = value;
  }

  bool showBalls() const noexcept
  {
    return _showBalls;
  }

  void showBalls( bool value ) noexcept
  {
    _showBalls = value;
  }

  double ballRadius() const noexcept
  {
    return _ballRadius;
  }

  void ballRadius( double radius )
  {
    _ballRadius = radius;
  }

private:

  /**
    Auxiliary function for creating a point in TikZ format. The point
    will be shown as a circle of a given size.

    @param out Output stream to which the point will be appended
    @param v   Vertex index
    @param p   Coordinates for the vertex (only two dimensions will be used)
  */

  template <class Coordinate, class Index> void writePoint( std::ostream& out, Index v, Coordinate& p )
  {
    auto x = p[0];
    auto y = p[1];

    out << "\\coordinate";

    if( _showVertexLabels )
      out << "[label=" << _labelPosition << ":" << std::to_string(v) << "] ";

    out << "(" << v << ") at (" << x << "," << y << ");\n";

    out << "\\filldraw[" << _pointColour << "]"
        << " " << "(" << v << ") circle (" << _pointSize << _pointSizeUnit << ");\n";

    if( _showBalls )
    {
      out << "\\fill[" << _ballColour << ","
          << " fill opacity=" << _ballOpacity
          << "]"
          << " " << "(" << v << ") circle (" << _ballRadius << "cm" << ");\n";
    }
  }

  /**
    Auxiliary function for creating an edge in TikZ format. The edge
    will be shown as a line connecting the two vertices.

    @param out Output stream to which the edge will be appended
    @param u   Source vertex index
    @param v   Target vertex index
  */

  template <class Index> void writeEdge( std::ostream& out, Index u, Index v )
  {
    out << "\\draw[" << _lineColour << ","
        << " line width=" << _lineWidth << _lineWidthUnit
        <<"]"
        << " " << "(" << u << ") -- (" << v << ");\n";
  }

  bool _showBalls         = false;
  double _ballOpacity     = 0.1;
  double _ballRadius      = 0.0;
  std::string _ballColour = "black";

  bool _showVertexLabels     = false;
  std::string _labelPosition = "above";

  // Node/vertex configuration options ---------------------------------

  std::string _pointColour   = "black";
  std::string _pointSizeUnit = "pt";
  double _pointSize          = 1;

  // Line/edge configuration options -----------------------------------

  std::string _lineColour    = "black";
  std::string _lineWidthUnit = "mm";
  double _lineWidth          = 0.50;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Started adding support for rendering $2$-simplices<commit_after>#ifndef ALEPH_TOPOLOGY_IO_TIKZ_HH__
#define ALEPH_TOPOLOGY_IO_TIKZ_HH__

#include <fstream>
#include <ostream>
#include <stdexcept>
#include <string>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class TikZ
  @brief Writes files as a TikZ picture

  This writer class uses coordinate information of a simplicial complex
  to represent its 1-skeleton, i.e. its vertices and edges. All data is
  stored as a picture for the TikZ LaTeX toolkit, resulting in a clean,
  modern output for publications.

  The output is configurable and permits the following adjustments:

    - point size
    - line width
*/

class TikZ
{
public:

  /** Writes the simplicial complex to a new file. */
  template <class SimplicialComplex, class Container> void operator()( const std::string& filename,
                                                                       const SimplicialComplex& K,
                                                                       const Container& container )
  {
    std::ofstream out( filename );
    if( !out )
      throw std::runtime_error( "Unable to open output file" );

    this->operator()( out, K, container );
  }

  /** Writes the simplicial complex to a new output stream. */
  template <class SimplicialComplex, class Container> void operator()( std::ostream& out,
                                                                       const SimplicialComplex& K,
                                                                       const Container& container )
  {
    out << "\\begin{tikzpicture}\n";

    // Render vertices as points ---------------------------------------

    out << "% 0-simplices\n";

    for( auto&& s : K )
    {
      if( s.dimension() != 0 )
        continue;

      auto u = s[0];         // vertex
      auto p = container[u]; // coordinate

      if( p.size() >= 2 )
        writePoint( out, u, p );
      else
        throw std::runtime_error( "Insufficient number of dimensions for storing coordinates" );
    }

    // Render edges as lines -------------------------------------------

    out << "% 1-simplices\n";

    for( auto&& s : K )
    {
      if( s.dimension() != 1 )
        continue;

      auto u = s[0];         // vertex
      auto v = s[1];         // vertex

      writeEdge(out, u, v);
    }

    // Render 2-simplices as triangles ----------------------------------

    if( _showTriangles )
    {
      out << "% 2-simplices\n";

      for( auto&& s : K )
      {
        if( s.dimension() != 2 )
          continue;

        auto u = s[0];
        auto v = s[1];
        auto w = s[2];

        writeTriangle(out, u, v, w);
      }
    }

    out << "\\end{tikzpicture}\n";
  }

  bool showVertexLabels() const noexcept
  {
    return _showVertexLabels;
  }

  void showVertexLabels( bool value ) noexcept
  {
    _showVertexLabels = value;
  }

  bool showBalls() const noexcept
  {
    return _showBalls;
  }

  void showBalls( bool value ) noexcept
  {
    _showBalls = value;
  }

  double ballRadius() const noexcept
  {
    return _ballRadius;
  }

  void ballRadius( double radius )
  {
    _ballRadius = radius;
  }

  bool showTriangles() const noexcept
  {
    return _showTriangles;
  }

  void showTriangles( bool value ) noexcept
  {
    _showTriangles = value;
  }

private:

  /**
    Auxiliary function for creating a point in TikZ format. The point
    will be shown as a circle of a given size.

    @param out Output stream to which the point will be appended
    @param v   Vertex index
    @param p   Coordinates for the vertex (only two dimensions will be used)
  */

  template <class Coordinate, class Index> void writePoint( std::ostream& out, Index v, Coordinate& p )
  {
    auto x = p[0];
    auto y = p[1];

    out << "\\coordinate";

    if( _showVertexLabels )
      out << "[label=" << _labelPosition << ":" << std::to_string(v) << "] ";

    out << "(" << v << ") at (" << x << "," << y << ");\n";

    out << "\\filldraw[" << _pointColour << "]"
        << " " << "(" << v << ") circle (" << _pointSize << _pointSizeUnit << ");\n";

    if( _showBalls )
    {
      out << "\\fill[" << _ballColour << ","
          << " fill opacity=" << _ballOpacity
          << "]"
          << " " << "(" << v << ") circle (" << _ballRadius << "cm" << ");\n";
    }
  }

  /**
    Auxiliary function for creating an edge in TikZ format. The edge
    will be shown as a line connecting the two vertices.

    @param out Output stream to which the edge will be appended
    @param u   Source vertex index
    @param v   Target vertex index
  */

  template <class Index> void writeEdge( std::ostream& out, Index u, Index v )
  {
    out << "\\draw[" << _lineColour << ","
        << " line width=" << _lineWidth << _lineWidthUnit
        <<"]"
        << " " << "(" << u << ") -- (" << v << ");\n";
  }

  /**
    Auxiliary function for creating a triangle in TikZ format. It is
    supposed to represent a 2-simplex.

    @param out Output stream to which the triangle will be appended
    @param u   First vertex index
    @param v   Second vertex index
    @param w   Third vertex index
  */

  template <class Index> void writeTriangle( std::ostream& out, Index u, Index v, Index w )
  {
    out << "\\filldraw[" << _triangleColour << ","
        << " fill opacity=" << _triangleOpacity
        <<"]"
        << " " << "(" << u << ") -- (" << v << ") -- (" << w << ") -- cycle;\n";
  }

  bool _showBalls         = false;
  double _ballOpacity     = 0.1;
  double _ballRadius      = 0.0;
  std::string _ballColour = "black";

  bool _showVertexLabels     = false;
  std::string _labelPosition = "above";

  // Node/vertex configuration options ---------------------------------

  std::string _pointColour   = "black";
  std::string _pointSizeUnit = "pt";
  double _pointSize          = 1;

  // Line/edge configuration options -----------------------------------

  std::string _lineColour    = "black";
  std::string _lineWidthUnit = "mm";
  double _lineWidth          = 0.50;

  // Triangles ---------------------------------------------------------

  bool _showTriangles         = false;
  std::string _triangleColour = "black";
  double _triangleOpacity     = 0.50;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2003-2011 Victor Semionov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the copyright holder nor the names of the contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <windows.h>

#include <gl/gl.h>

#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>

#include "Window.h"
#include "Body.h"
#include "Error.h"
#include "Info.h"

#define NAME_FONT_NAME "Arial"
#define NAME_FONT_SIZE_AT_H600 24
#define NAME_FONT_SIZE (int)(NAME_FONT_SIZE_AT_H600*scrheight/600)

#define NAME_TEXT_COLOR_R 1.00f
#define NAME_TEXT_COLOR_G 1.00f
#define NAME_TEXT_COLOR_B 1.00f
#define NAME_TEXT_COLOR_A 0.50f

#define INFO_FONT_NAME "Arial"
#define INFO_FONT_SIZE_AT_H600 16
#define INFO_FONT_SIZE (int)(INFO_FONT_SIZE_AT_H600*scrheight/600)

#define INFO_TEXT_COLOR_R 1.00f
#define INFO_TEXT_COLOR_G 1.00f
#define INFO_TEXT_COLOR_B 1.00f
#define INFO_TEXT_COLOR_A 0.50f

#define SCREEN_SIZE_RATIO_STD (4.0f/3.0f)
#define FONT_SIZE_COEFF (4.6f/3.0f) // do not change!
#define SPACING_COEF 1.15f
#define LINES_AFTER_NAME 1.125f

#define WINDOW_COLOR_R 0.50f
#define WINDOW_COLOR_G 0.50f
#define WINDOW_COLOR_B 0.50f
#define WINDOW_COLOR_A 0.25f

#define MAX_FADE_TIME 3.0f
#define FADE_TIME_RATIO 0.10f
#define FADE_TIME(totaltime) min(MAX_FADE_TIME, (totaltime)*FADE_TIME_RATIO)

#define WINDOW_BORDER_REL 0.0125f
#define WINDOW_BORDER (int)(WINDOW_BORDER_REL*scrheight)

#define MARGIN_TOP_REL 0.0250f
#define MARGIN_BOTTOM_REL 0.0050f
#define MARGIN_LEFT_REL (0.0200f*SCREEN_SIZE_RATIO_STD)
#define MARGIN_LEFT_WIDTH (int)(MARGIN_LEFT_REL*scrheight)
#define MARGIN_TOP_HEIGHT (int)(MARGIN_TOP_REL*scrheight)
#define MARGIN_BOTTOM_HEIGHT (int)(MARGIN_BOTTOM_REL*scrheight)

#define WINDOW_WIDTH_REL_Y (0.3050f*SCREEN_SIZE_RATIO_STD)
#define WINDOW_WIDTH (int)(WINDOW_WIDTH_REL_Y*scrheight)
#define WINDOW_HEIGHT (MARGIN_TOP_HEIGHT+MARGIN_BOTTOM_HEIGHT+(int)(NAME_FONT_SIZE*LINES_AFTER_NAME*SPACING_COEF*FONT_SIZE_COEFF)+3*(int)(INFO_FONT_SIZE*SPACING_COEF*FONT_SIZE_COEFF))

#define WINDOW_POS_X1 (WINDOW_BORDER)
#define WINDOW_POS_Y1 (WINDOW_BORDER)
#define WINDOW_POS_X2 (WINDOW_POS_X1+WINDOW_WIDTH)
#define WINDOW_POS_Y2 (WINDOW_POS_Y1+WINDOW_HEIGHT)

CInfo::CInfo()
{
	Init();
}

CInfo::~CInfo()
{
	Free();
}

void CInfo::Init()
{
	loaded=false;
	scrwidth=0;
	scrheight=0;
	winlist=0;
	namelist=infolist=0;
	time=0;
	starttime=endtime=0;
	fadetime=1;
	alpha=0;
}

void CInfo::Free()
{
	nametext.Free();
	infotext.Free();
	if (winlist)
	{
		if (glIsList(winlist))
			glDeleteLists(winlist,3);
	}
	Init();
}

bool CInfo::Load()
{
	Free();

	scrwidth=CWindow::GetWidth();
	scrheight=CWindow::GetHeight();

	winlist=glGenLists(3);
	if (!winlist)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to generate display lists.");
		Free();
		return false;
	}
	namelist=winlist+1;
	infolist=namelist+1;

	MakeWindow(winlist);

	loaded=true;
	loaded&=nametext.BuildFTFont(NAME_FONT_NAME,NAME_FONT_SIZE);
	loaded&=infotext.BuildFTFont(INFO_FONT_NAME,INFO_FONT_SIZE);
	if (!loaded)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to load font.");
		Free();
	}

	return loaded;
}

void CInfo::MakeWindow(int list)
{
	glNewList(list,GL_COMPILE);
	{
		int l=WINDOW_POS_X1;
		int r=WINDOW_POS_X2;
		int b=WINDOW_POS_Y1;
		int t=WINDOW_POS_Y2;
		glDisable(GL_TEXTURE_2D);
		glLoadIdentity();
		glBegin(GL_QUADS);
		{
			glVertex2f((float)l,(float)b);
			glVertex2f((float)r,(float)b);
			glVertex2f((float)r,(float)t);
			glVertex2f((float)l,(float)t);
		}
		glEnd();
	}
	glEndList();
}

void CInfo::GetNameCoords(const char *text, int *x, int *y)
{
	float tw;
	nametext.GetTextSize(text,&tw,NULL);
	int th=NAME_FONT_SIZE;

	if (x) *x=WINDOW_POS_X1+(WINDOW_WIDTH-(int)tw)/2;
	if (y) *y=WINDOW_POS_Y2-MARGIN_TOP_HEIGHT-th;
}

void CInfo::GetInfoCoords(int linenum, int *x, int *y)
{
	int ymargin=WINDOW_POS_Y2-MARGIN_TOP_HEIGHT;

	float nameheight;
	nametext.GetTextSize("",NULL,&nameheight);

	float nameadd;
	nameadd=nameheight*SPACING_COEF*LINES_AFTER_NAME;

	int ioffset=INFO_FONT_SIZE;

	float th;
	infotext.GetTextSize("",NULL,&th);
	th*=SPACING_COEF;
	int thi=(int)th*(linenum-1);

	if (x) *x=WINDOW_POS_X1+MARGIN_LEFT_WIDTH;
	if (y) *y=ymargin-(int)nameadd-ioffset-thi;
}

void CInfo::MakeName(int list, char *targetname)
{
	if (!targetname) return;
	if (*targetname==' ') targetname++;
	int x,y;
	GetNameCoords(targetname,&x,&y);
	glNewList(list,GL_COMPILE);
	{
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		glTranslatef((float)x,(float)y,0);
		nametext.Print(targetname);
	}
	glEndList();
}

void CInfo::MakeInfoLine(int linenum, char *line)
{
	int x,y;
	GetInfoCoords(linenum,&x,&y);
	glPushMatrix();
	glTranslatef((float)x,(float)y,0);
	infotext.Print(line);
	glPopMatrix();
}

void CInfo::MakeInfo(int list, CBody *targetbody)
{
	bool star=(targetbody==NULL);
	if (star) targetbody=CBody::bodycache[0];
	glNewList(list,GL_COMPILE);
	{
		int n=0;
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		if (star)
		{
			char line[64];
			n++;
			sprintf(line,"star name: %s",targetbody->name);
			MakeInfoLine(n,line);
		}
		for (int i=0;i<targetbody->info.numlines;i++)
		{
			if (targetbody->info.textlines[i][0]=='/') continue;
			n++;
			MakeInfoLine(n,targetbody->info.textlines[i]);
		}
	}
	glEndList();
}

void CInfo::Start(float seconds, float duration, char *targetname, CBody *targetbody)
{
	if (!loaded)
		return;
	char name[32];
	strcpy(name,targetname);
	int l=strlen(name);
	for (int i=0;i<l;i++)
		if (name[i]=='_')
			name[i]=' ';
	starttime=seconds;
	endtime=starttime+duration;
	fadetime=FADE_TIME(duration);
	MakeName(namelist,name);
	MakeInfo(infolist,targetbody);
}

void CInfo::Update(float seconds)
{
	time=seconds;
	if (time<(endtime-fadetime))
		alpha=min(1,(time-starttime)/fadetime);
	else
		alpha=max(0,(endtime-time)/fadetime);
}

void CInfo::Restart()
{
	starttime-=time;
	endtime-=time;
	time=0;
}

void CInfo::Draw()
{
	if (!alpha || !loaded)
		return;

	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glEnable(GL_BLEND);

	glColor4f(WINDOW_COLOR_R,WINDOW_COLOR_G,WINDOW_COLOR_B,WINDOW_COLOR_A*alpha);
	glCallList(winlist);

	glColor4f(NAME_TEXT_COLOR_R,NAME_TEXT_COLOR_G,NAME_TEXT_COLOR_B,NAME_TEXT_COLOR_A*alpha);
	glCallList(namelist);

	glColor4f(INFO_TEXT_COLOR_R,INFO_TEXT_COLOR_G,INFO_TEXT_COLOR_B,INFO_TEXT_COLOR_A*alpha);
	glCallList(infolist);
}
<commit_msg>Refactoring - trim underscores and spaces from body names.<commit_after>/*
 * Copyright (C) 2003-2011 Victor Semionov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the copyright holder nor the names of the contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <windows.h>

#include <gl/gl.h>

#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>

#include "Window.h"
#include "Body.h"
#include "Error.h"
#include "Info.h"

#define NAME_FONT_NAME "Arial"
#define NAME_FONT_SIZE_AT_H600 24
#define NAME_FONT_SIZE (int)(NAME_FONT_SIZE_AT_H600*scrheight/600)

#define NAME_TEXT_COLOR_R 1.00f
#define NAME_TEXT_COLOR_G 1.00f
#define NAME_TEXT_COLOR_B 1.00f
#define NAME_TEXT_COLOR_A 0.50f

#define INFO_FONT_NAME "Arial"
#define INFO_FONT_SIZE_AT_H600 16
#define INFO_FONT_SIZE (int)(INFO_FONT_SIZE_AT_H600*scrheight/600)

#define INFO_TEXT_COLOR_R 1.00f
#define INFO_TEXT_COLOR_G 1.00f
#define INFO_TEXT_COLOR_B 1.00f
#define INFO_TEXT_COLOR_A 0.50f

#define SCREEN_SIZE_RATIO_STD (4.0f/3.0f)
#define FONT_SIZE_COEFF (4.6f/3.0f) // do not change!
#define SPACING_COEF 1.15f
#define LINES_AFTER_NAME 1.125f

#define WINDOW_COLOR_R 0.50f
#define WINDOW_COLOR_G 0.50f
#define WINDOW_COLOR_B 0.50f
#define WINDOW_COLOR_A 0.25f

#define MAX_FADE_TIME 3.0f
#define FADE_TIME_RATIO 0.10f
#define FADE_TIME(totaltime) min(MAX_FADE_TIME, (totaltime)*FADE_TIME_RATIO)

#define WINDOW_BORDER_REL 0.0125f
#define WINDOW_BORDER (int)(WINDOW_BORDER_REL*scrheight)

#define MARGIN_TOP_REL 0.0250f
#define MARGIN_BOTTOM_REL 0.0050f
#define MARGIN_LEFT_REL (0.0200f*SCREEN_SIZE_RATIO_STD)
#define MARGIN_LEFT_WIDTH (int)(MARGIN_LEFT_REL*scrheight)
#define MARGIN_TOP_HEIGHT (int)(MARGIN_TOP_REL*scrheight)
#define MARGIN_BOTTOM_HEIGHT (int)(MARGIN_BOTTOM_REL*scrheight)

#define WINDOW_WIDTH_REL_Y (0.3050f*SCREEN_SIZE_RATIO_STD)
#define WINDOW_WIDTH (int)(WINDOW_WIDTH_REL_Y*scrheight)
#define WINDOW_HEIGHT (MARGIN_TOP_HEIGHT+MARGIN_BOTTOM_HEIGHT+(int)(NAME_FONT_SIZE*LINES_AFTER_NAME*SPACING_COEF*FONT_SIZE_COEFF)+3*(int)(INFO_FONT_SIZE*SPACING_COEF*FONT_SIZE_COEFF))

#define WINDOW_POS_X1 (WINDOW_BORDER)
#define WINDOW_POS_Y1 (WINDOW_BORDER)
#define WINDOW_POS_X2 (WINDOW_POS_X1+WINDOW_WIDTH)
#define WINDOW_POS_Y2 (WINDOW_POS_Y1+WINDOW_HEIGHT)

CInfo::CInfo()
{
	Init();
}

CInfo::~CInfo()
{
	Free();
}

void CInfo::Init()
{
	loaded=false;
	scrwidth=0;
	scrheight=0;
	winlist=0;
	namelist=infolist=0;
	time=0;
	starttime=endtime=0;
	fadetime=1;
	alpha=0;
}

void CInfo::Free()
{
	nametext.Free();
	infotext.Free();
	if (winlist)
	{
		if (glIsList(winlist))
			glDeleteLists(winlist,3);
	}
	Init();
}

bool CInfo::Load()
{
	Free();

	scrwidth=CWindow::GetWidth();
	scrheight=CWindow::GetHeight();

	winlist=glGenLists(3);
	if (!winlist)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to generate display lists.");
		Free();
		return false;
	}
	namelist=winlist+1;
	infolist=namelist+1;

	MakeWindow(winlist);

	loaded=true;
	loaded&=nametext.BuildFTFont(NAME_FONT_NAME,NAME_FONT_SIZE);
	loaded&=infotext.BuildFTFont(INFO_FONT_NAME,INFO_FONT_SIZE);
	if (!loaded)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to load font.");
		Free();
	}

	return loaded;
}

void CInfo::MakeWindow(int list)
{
	glNewList(list,GL_COMPILE);
	{
		int l=WINDOW_POS_X1;
		int r=WINDOW_POS_X2;
		int b=WINDOW_POS_Y1;
		int t=WINDOW_POS_Y2;
		glDisable(GL_TEXTURE_2D);
		glLoadIdentity();
		glBegin(GL_QUADS);
		{
			glVertex2f((float)l,(float)b);
			glVertex2f((float)r,(float)b);
			glVertex2f((float)r,(float)t);
			glVertex2f((float)l,(float)t);
		}
		glEnd();
	}
	glEndList();
}

void CInfo::GetNameCoords(const char *text, int *x, int *y)
{
	float tw;
	nametext.GetTextSize(text,&tw,NULL);
	int th=NAME_FONT_SIZE;

	if (x) *x=WINDOW_POS_X1+(WINDOW_WIDTH-(int)tw)/2;
	if (y) *y=WINDOW_POS_Y2-MARGIN_TOP_HEIGHT-th;
}

void CInfo::GetInfoCoords(int linenum, int *x, int *y)
{
	int ymargin=WINDOW_POS_Y2-MARGIN_TOP_HEIGHT;

	float nameheight;
	nametext.GetTextSize("",NULL,&nameheight);

	float nameadd;
	nameadd=nameheight*SPACING_COEF*LINES_AFTER_NAME;

	int ioffset=INFO_FONT_SIZE;

	float th;
	infotext.GetTextSize("",NULL,&th);
	th*=SPACING_COEF;
	int thi=(int)th*(linenum-1);

	if (x) *x=WINDOW_POS_X1+MARGIN_LEFT_WIDTH;
	if (y) *y=ymargin-(int)nameadd-ioffset-thi;
}

void CInfo::MakeName(int list, char *targetname)
{
	if (!targetname) return;
	int x,y;
	GetNameCoords(targetname,&x,&y);
	glNewList(list,GL_COMPILE);
	{
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		glTranslatef((float)x,(float)y,0);
		nametext.Print(targetname);
	}
	glEndList();
}

void CInfo::MakeInfoLine(int linenum, char *line)
{
	int x,y;
	GetInfoCoords(linenum,&x,&y);
	glPushMatrix();
	glTranslatef((float)x,(float)y,0);
	infotext.Print(line);
	glPopMatrix();
}

void CInfo::MakeInfo(int list, CBody *targetbody)
{
	bool star=(targetbody==NULL);
	if (star) targetbody=CBody::bodycache[0];
	glNewList(list,GL_COMPILE);
	{
		int n=0;
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		if (star)
		{
			char line[64];
			n++;
			sprintf(line,"star name: %s",targetbody->name);
			MakeInfoLine(n,line);
		}
		for (int i=0;i<targetbody->info.numlines;i++)
		{
			if (targetbody->info.textlines[i][0]=='/') continue;
			n++;
			MakeInfoLine(n,targetbody->info.textlines[i]);
		}
	}
	glEndList();
}

void CInfo::Start(float seconds, float duration, char *targetname, CBody *targetbody)
{
	int l;
	int i;
	int idx;
	char name[32];
	if (!loaded)
		return;
	strcpy(name,targetname);
	l=strlen(name);
	for (i=0;i<l;i++)
		if (name[i]=='_')
			name[i]=' ';
	for (i=l-1;i>=0;i--)
	{
		if (name[i]!=' ')
			break;
		name[i]=0;
	}
	for (idx=0;idx<l;idx++)
		if (name[idx]!=' ')
			break;
	starttime=seconds;
	endtime=starttime+duration;
	fadetime=FADE_TIME(duration);
	MakeName(namelist,name+idx);
	MakeInfo(infolist,targetbody);
}

void CInfo::Update(float seconds)
{
	time=seconds;
	if (time<(endtime-fadetime))
		alpha=min(1,(time-starttime)/fadetime);
	else
		alpha=max(0,(endtime-time)/fadetime);
}

void CInfo::Restart()
{
	starttime-=time;
	endtime-=time;
	time=0;
}

void CInfo::Draw()
{
	if (!alpha || !loaded)
		return;

	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glEnable(GL_BLEND);

	glColor4f(WINDOW_COLOR_R,WINDOW_COLOR_G,WINDOW_COLOR_B,WINDOW_COLOR_A*alpha);
	glCallList(winlist);

	glColor4f(NAME_TEXT_COLOR_R,NAME_TEXT_COLOR_G,NAME_TEXT_COLOR_B,NAME_TEXT_COLOR_A*alpha);
	glCallList(namelist);

	glColor4f(INFO_TEXT_COLOR_R,INFO_TEXT_COLOR_G,INFO_TEXT_COLOR_B,INFO_TEXT_COLOR_A*alpha);
	glCallList(infolist);
}
<|endoftext|>


<commit_before>#include "mpdas.h"

#define APIKEY		"a0ed2629d3d28606f67d7214c916788d"
#define	SECRET		"295f31c5d28215215b1503fb0327cc01"
#define CURL_MAX_RETRIES 3
#define CURL_RETRY_DELAY 3 // Seconds

CAudioScrobbler* AudioScrobbler = 0;

#define CLEANUP()	_response.clear()

size_t writecb(void* ptr, size_t size, size_t nmemb, void *stream)
{
    AudioScrobbler->ReportResponse((char*)ptr, size*nmemb);
    return size*nmemb;
}

CAudioScrobbler::CAudioScrobbler()
{
    _failcount = 0;
    _authed = false;
    _response = "";
    _handle = curl_easy_init();
    if(!_handle) {
	eprintf("%s", "Could not initialize CURL.");
	exit(EXIT_FAILURE);
    }
}

CAudioScrobbler::~CAudioScrobbler()
{
    curl_easy_cleanup(_handle);
    curl_global_cleanup();
}

std::string CAudioScrobbler::GetServiceURL()
{
    if(Config->getService() == LibreFm) {
	return "https://libre.fm/2.0/";
    }
    return "http://ws.audioscrobbler.com/2.0/";
}

void CAudioScrobbler::OpenURL(std::string url, const char* postfields = 0, char* errbuf = 0)
{
    curl_easy_setopt(_handle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
    curl_easy_setopt(_handle, CURLOPT_NOPROGRESS, 1);
    curl_easy_setopt(_handle, CURLOPT_WRITEFUNCTION, writecb);
    curl_easy_setopt(_handle, CURLOPT_TIMEOUT, 10);

    if(postfields) {
	curl_easy_setopt(_handle, CURLOPT_POST, 1);
	curl_easy_setopt(_handle, CURLOPT_POSTFIELDS, postfields);
    }
    else
	curl_easy_setopt(_handle, CURLOPT_POST, 0);
    if(errbuf)
	curl_easy_setopt(_handle, CURLOPT_ERRORBUFFER, errbuf);

    curl_easy_setopt(_handle, CURLOPT_URL, url.c_str());
    CURLcode res = curl_easy_perform(_handle);

    // Sometimes last.fm likes to just timeout for no reason, leaving us hanging.
    // If this happens, retry a few times with a small delay.
    if (res != CURLE_OK) {
        eprintf("libcurl: (%d)", res);
        eprintf("%s", curl_easy_strerror(res));
        eprintf("Will retry %d times with a %d second delay.", CURL_MAX_RETRIES, CURL_RETRY_DELAY);

        int retries = 0;
        do {
            sleep(CURL_RETRY_DELAY);
            retries++;
            eprintf("Retry %d/%d", retries, CURL_MAX_RETRIES);
            res = curl_easy_perform(_handle);
        } while (res != CURLE_OK || retries < CURL_MAX_RETRIES);

        eprintf("Failed after %d retries, try again later.", CURL_MAX_RETRIES);
    }
}

void CAudioScrobbler::ReportResponse(char* buf, size_t size)
{
    _response.append(buf);
}

std::string CAudioScrobbler::CreateScrobbleMessage(int index, const CacheEntry& entry)
{
    const Song& song = entry.getSong();
    std::ostringstream msg, sigmsg ;
    std::string artist, title, album, array = "=";

    char* temp = 0;
    temp = curl_easy_escape(_handle, song.getArtist().c_str(), song.getArtist().length());
    artist = temp;
    curl_free(temp);
    temp = curl_easy_escape(_handle, song.getTitle().c_str(), song.getTitle().length());
    title = temp;
    curl_free(temp);
    temp = curl_easy_escape(_handle, song.getAlbum().c_str(), song.getAlbum().length());
    album = temp;
    curl_free(temp);

    msg << "&album" << array << album;
    msg << "&api_key=" << APIKEY;
    msg << "&artist" << array << artist;
    msg << "&duration" << array << song.getDuration();
    msg << "&method=track.Scrobble";
    msg << "&timestamp" << array << entry.getStartTime();
    msg << "&track" << array << title;
    msg << "&sk=" << _sessionid;

    array = "";

    sigmsg << "album" << array << song.getAlbum();
    sigmsg << "api_key" << APIKEY;
    sigmsg << "artist" << array << song.getArtist();
    sigmsg << "duration" << array << song.getDuration();
    sigmsg << "methodtrack.Scrobble";
    sigmsg << "sk" << _sessionid;
    sigmsg << "timestamp" << array << entry.getStartTime();
    sigmsg << "track" << array << song.getTitle();
    sigmsg << SECRET;

    std::string sighash(md5sum((char*)"%s", sigmsg.str().c_str()));
    msg << "&api_sig=" << sighash;

    return msg.str();
}

void CAudioScrobbler::Failure()
{
    _failcount += 1;
    if(_failcount >= 3) {
	eprintf("%s", "Re-Handshaking!");
	_failcount = 0;
	Handshake();
    }
}

bool CAudioScrobbler::CheckFailure(std::string response)
{
    bool retval = false;

    size_t start, end;
    start = _response.find("<error code=\"")+13;
    end = _response.find(">", start)-1;
    std::string errorcode = _response.substr(start, end-start);
    int code = strtol(errorcode.c_str(), 0, 10);

    eprintf("%s%i", "Code: ", code);

    switch(code) {
	case 3:
	    eprintf("Invalid Method. This should not happen.");
	    retval = true;
	    break;
	case 4:
	    eprintf("Authentication failed. Please check your login data.");
	    exit(EXIT_FAILURE);
	case 9:
	    eprintf("Invalid session key. Re-authenticating.");
	    retval = true;
	    _failcount = 3;
	    break;
	case 10:
	    eprintf("Invalid API-Key. Let's bugger off.");
	    exit(EXIT_FAILURE);
	case 16:
	    eprintf("The service is temporarily unavailable, we will try again later..");
	    retval = true;
	    break;
	case 26:
	    eprintf("Uh oh. Suspended API key - Access for your account has been suspended, please contact Last.fm");
	    exit(EXIT_FAILURE);
    }

    return retval;
}

bool CAudioScrobbler::Scrobble(const CacheEntry& entry)
{
    bool retval = false;
    if(!_authed) {
	eprintf("Handshake hasn't been done yet.");
	Handshake();
	return retval;
    }
    iprintf("Scrobbling: %s - %s", entry.getSong().getArtist().c_str(), entry.getSong().getTitle().c_str());

    OpenURL(GetServiceURL(), CreateScrobbleMessage(0, entry).c_str());
    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	iprintf("%s", "Scrobbled successfully.");
	retval = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	eprintf("%s%s", "Last.fm returned an error while scrobbling:\n", _response.c_str());
	if(CheckFailure(_response))
	    Failure();
    }
    CLEANUP();

    return retval;
}

bool CAudioScrobbler::LoveTrack(const Song& song, bool unlove)
{
    bool retval = false;

    char* artist = curl_easy_escape(_handle, song.getArtist().c_str(), 0);
    char* title = curl_easy_escape(_handle, song.getTitle().c_str(), 0);

    std::ostringstream query, sig;
    query << (unlove ? "method=track.unlove&" : "method=track.love&")
	<< "&track=" << title
	<< "&artist=" << artist
	<< "&api_key=" << APIKEY
	<< "&sk=" << _sessionid;

    curl_free(artist);
    curl_free(title);

    sig << "api_key" << APIKEY
	<< "artist" << song.getArtist()
	<< "method" << (unlove ? "track.unlove" : "track.love")
	<< "sk" << _sessionid
	<< "track" << song.getTitle()
	<< SECRET;

    std::string sighash(md5sum((char*)"%s", sig.str().c_str()));

    query << "&api_sig=" << sighash;

    OpenURL(GetServiceURL(), query.str().c_str());

    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	iprintf("%s", "(Un)loved track successfully.");
	retval = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	eprintf("%s%s", "Last.fm returned an error while (un)loving the currently playing track:\n", _response.c_str());
	if(CheckFailure(_response))
	    Failure();
    }

    CLEANUP();
    return retval;
}

bool CAudioScrobbler::SendNowPlaying(const Song& song)
{
    bool retval = false;

    char* artist = curl_easy_escape(_handle, song.getArtist().c_str(), 0);
    char* title = curl_easy_escape(_handle, song.getTitle().c_str(), 0);
    char* album = song.getAlbum().empty() ? 0 : curl_easy_escape(_handle, song.getAlbum().c_str(), 0);

    std::ostringstream query, sig;
    query << "method=track.updateNowPlaying&track=" << title
	<< "&artist=" << artist
	<< "&duration=" << song.getDuration()
	<< "&api_key=" << APIKEY
	<< "&sk=" << _sessionid;
    if(album) {
	query << "&album=" << album;
	sig << "album" << song.getAlbum();
    }

    curl_free(artist);
    curl_free(title);
    curl_free(album);

    sig << "api_key" << APIKEY
	<< "artist" << song.getArtist()
	<< "duration" << song.getDuration()
	<< "methodtrack.updateNowPlaying"
	<< "sk" << _sessionid
	<< "track" << song.getTitle()
	<< SECRET;

    std::string sighash(md5sum((char*)"%s", sig.str().c_str()));

    query << "&api_sig=" << sighash;

    OpenURL(GetServiceURL(), query.str().c_str());

    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	iprintf("%s", "Updated \"Now Playing\" status successfully.");
	retval = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	eprintf("%s%s", "Last.fm returned an error while updating the currently playing track:\n", _response.c_str());
	if(CheckFailure(_response))
	    Failure();
    }

    CLEANUP();
    return retval;
}

void CAudioScrobbler::Handshake()
{
    std::string username="";
    for(unsigned int i = 0; i < Config->getLUsername().length(); i++) {
	username.append(1, tolower(Config->getLUsername().c_str()[i]));
    }
    std::string authtoken(md5sum((char*)"%s%s", username.c_str(), Config->getLPassword().c_str()));

    std::ostringstream query, sig;
    query << "method=auth.getMobileSession&username=" << username << "&authToken=" << authtoken << "&api_key=" << APIKEY;

    sig << "api_key" << APIKEY << "authToken" << authtoken << "methodauth.getMobileSessionusername" << username << SECRET;
    std::string sighash(md5sum((char*)"%s", sig.str().c_str()));

    query << "&api_sig=" << sighash;

    OpenURL(GetServiceURL(), query.str().c_str());

    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	size_t start, end;
	start = _response.find("<key>") + 5;
	end = _response.find("</key>");
	_sessionid = _response.substr(start, end-start);
	iprintf("%s%s", "Last.fm handshake successful. SessionID: ", _sessionid.c_str());
	_authed = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	CheckFailure(_response);
	exit(EXIT_FAILURE);
    }

    CLEANUP();
}
<commit_msg>|| -> &&<commit_after>#include "mpdas.h"

#define APIKEY		"a0ed2629d3d28606f67d7214c916788d"
#define	SECRET		"295f31c5d28215215b1503fb0327cc01"
#define CURL_MAX_RETRIES 3
#define CURL_RETRY_DELAY 3 // Seconds

CAudioScrobbler* AudioScrobbler = 0;

#define CLEANUP()	_response.clear()

size_t writecb(void* ptr, size_t size, size_t nmemb, void *stream)
{
    AudioScrobbler->ReportResponse((char*)ptr, size*nmemb);
    return size*nmemb;
}

CAudioScrobbler::CAudioScrobbler()
{
    _failcount = 0;
    _authed = false;
    _response = "";
    _handle = curl_easy_init();
    if(!_handle) {
	eprintf("%s", "Could not initialize CURL.");
	exit(EXIT_FAILURE);
    }
}

CAudioScrobbler::~CAudioScrobbler()
{
    curl_easy_cleanup(_handle);
    curl_global_cleanup();
}

std::string CAudioScrobbler::GetServiceURL()
{
    if(Config->getService() == LibreFm) {
	return "https://libre.fm/2.0/";
    }
    return "http://ws.audioscrobbler.com/2.0/";
}

void CAudioScrobbler::OpenURL(std::string url, const char* postfields = 0, char* errbuf = 0)
{
    curl_easy_setopt(_handle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
    curl_easy_setopt(_handle, CURLOPT_NOPROGRESS, 1);
    curl_easy_setopt(_handle, CURLOPT_WRITEFUNCTION, writecb);
    curl_easy_setopt(_handle, CURLOPT_TIMEOUT, 10);

    if(postfields) {
	curl_easy_setopt(_handle, CURLOPT_POST, 1);
	curl_easy_setopt(_handle, CURLOPT_POSTFIELDS, postfields);
    }
    else
	curl_easy_setopt(_handle, CURLOPT_POST, 0);
    if(errbuf)
	curl_easy_setopt(_handle, CURLOPT_ERRORBUFFER, errbuf);

    curl_easy_setopt(_handle, CURLOPT_URL, url.c_str());
    CURLcode res = curl_easy_perform(_handle);

    // Sometimes last.fm likes to just timeout for no reason, leaving us hanging.
    // If this happens, retry a few times with a small delay.
    if (res != CURLE_OK) {
        eprintf("libcurl: (%d)", res);
        eprintf("%s", curl_easy_strerror(res));
        eprintf("Will retry %d times with a %d second delay.", CURL_MAX_RETRIES, CURL_RETRY_DELAY);

        int retries = 0;
        do {
            sleep(CURL_RETRY_DELAY);
            retries++;
            eprintf("Retry %d/%d", retries, CURL_MAX_RETRIES);
            res = curl_easy_perform(_handle);
        } while (res != CURLE_OK && retries < CURL_MAX_RETRIES);

        eprintf("Failed after %d retries, try again later.", CURL_MAX_RETRIES);
    }
}

void CAudioScrobbler::ReportResponse(char* buf, size_t size)
{
    _response.append(buf);
}

std::string CAudioScrobbler::CreateScrobbleMessage(int index, const CacheEntry& entry)
{
    const Song& song = entry.getSong();
    std::ostringstream msg, sigmsg ;
    std::string artist, title, album, array = "=";

    char* temp = 0;
    temp = curl_easy_escape(_handle, song.getArtist().c_str(), song.getArtist().length());
    artist = temp;
    curl_free(temp);
    temp = curl_easy_escape(_handle, song.getTitle().c_str(), song.getTitle().length());
    title = temp;
    curl_free(temp);
    temp = curl_easy_escape(_handle, song.getAlbum().c_str(), song.getAlbum().length());
    album = temp;
    curl_free(temp);

    msg << "&album" << array << album;
    msg << "&api_key=" << APIKEY;
    msg << "&artist" << array << artist;
    msg << "&duration" << array << song.getDuration();
    msg << "&method=track.Scrobble";
    msg << "&timestamp" << array << entry.getStartTime();
    msg << "&track" << array << title;
    msg << "&sk=" << _sessionid;

    array = "";

    sigmsg << "album" << array << song.getAlbum();
    sigmsg << "api_key" << APIKEY;
    sigmsg << "artist" << array << song.getArtist();
    sigmsg << "duration" << array << song.getDuration();
    sigmsg << "methodtrack.Scrobble";
    sigmsg << "sk" << _sessionid;
    sigmsg << "timestamp" << array << entry.getStartTime();
    sigmsg << "track" << array << song.getTitle();
    sigmsg << SECRET;

    std::string sighash(md5sum((char*)"%s", sigmsg.str().c_str()));
    msg << "&api_sig=" << sighash;

    return msg.str();
}

void CAudioScrobbler::Failure()
{
    _failcount += 1;
    if(_failcount >= 3) {
	eprintf("%s", "Re-Handshaking!");
	_failcount = 0;
	Handshake();
    }
}

bool CAudioScrobbler::CheckFailure(std::string response)
{
    bool retval = false;

    size_t start, end;
    start = _response.find("<error code=\"")+13;
    end = _response.find(">", start)-1;
    std::string errorcode = _response.substr(start, end-start);
    int code = strtol(errorcode.c_str(), 0, 10);

    eprintf("%s%i", "Code: ", code);

    switch(code) {
	case 3:
	    eprintf("Invalid Method. This should not happen.");
	    retval = true;
	    break;
	case 4:
	    eprintf("Authentication failed. Please check your login data.");
	    exit(EXIT_FAILURE);
	case 9:
	    eprintf("Invalid session key. Re-authenticating.");
	    retval = true;
	    _failcount = 3;
	    break;
	case 10:
	    eprintf("Invalid API-Key. Let's bugger off.");
	    exit(EXIT_FAILURE);
	case 16:
	    eprintf("The service is temporarily unavailable, we will try again later..");
	    retval = true;
	    break;
	case 26:
	    eprintf("Uh oh. Suspended API key - Access for your account has been suspended, please contact Last.fm");
	    exit(EXIT_FAILURE);
    }

    return retval;
}

bool CAudioScrobbler::Scrobble(const CacheEntry& entry)
{
    bool retval = false;
    if(!_authed) {
	eprintf("Handshake hasn't been done yet.");
	Handshake();
	return retval;
    }
    iprintf("Scrobbling: %s - %s", entry.getSong().getArtist().c_str(), entry.getSong().getTitle().c_str());

    OpenURL(GetServiceURL(), CreateScrobbleMessage(0, entry).c_str());
    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	iprintf("%s", "Scrobbled successfully.");
	retval = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	eprintf("%s%s", "Last.fm returned an error while scrobbling:\n", _response.c_str());
	if(CheckFailure(_response))
	    Failure();
    }
    CLEANUP();

    return retval;
}

bool CAudioScrobbler::LoveTrack(const Song& song, bool unlove)
{
    bool retval = false;

    char* artist = curl_easy_escape(_handle, song.getArtist().c_str(), 0);
    char* title = curl_easy_escape(_handle, song.getTitle().c_str(), 0);

    std::ostringstream query, sig;
    query << (unlove ? "method=track.unlove&" : "method=track.love&")
	<< "&track=" << title
	<< "&artist=" << artist
	<< "&api_key=" << APIKEY
	<< "&sk=" << _sessionid;

    curl_free(artist);
    curl_free(title);

    sig << "api_key" << APIKEY
	<< "artist" << song.getArtist()
	<< "method" << (unlove ? "track.unlove" : "track.love")
	<< "sk" << _sessionid
	<< "track" << song.getTitle()
	<< SECRET;

    std::string sighash(md5sum((char*)"%s", sig.str().c_str()));

    query << "&api_sig=" << sighash;

    OpenURL(GetServiceURL(), query.str().c_str());

    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	iprintf("%s", "(Un)loved track successfully.");
	retval = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	eprintf("%s%s", "Last.fm returned an error while (un)loving the currently playing track:\n", _response.c_str());
	if(CheckFailure(_response))
	    Failure();
    }

    CLEANUP();
    return retval;
}

bool CAudioScrobbler::SendNowPlaying(const Song& song)
{
    bool retval = false;

    char* artist = curl_easy_escape(_handle, song.getArtist().c_str(), 0);
    char* title = curl_easy_escape(_handle, song.getTitle().c_str(), 0);
    char* album = song.getAlbum().empty() ? 0 : curl_easy_escape(_handle, song.getAlbum().c_str(), 0);

    std::ostringstream query, sig;
    query << "method=track.updateNowPlaying&track=" << title
	<< "&artist=" << artist
	<< "&duration=" << song.getDuration()
	<< "&api_key=" << APIKEY
	<< "&sk=" << _sessionid;
    if(album) {
	query << "&album=" << album;
	sig << "album" << song.getAlbum();
    }

    curl_free(artist);
    curl_free(title);
    curl_free(album);

    sig << "api_key" << APIKEY
	<< "artist" << song.getArtist()
	<< "duration" << song.getDuration()
	<< "methodtrack.updateNowPlaying"
	<< "sk" << _sessionid
	<< "track" << song.getTitle()
	<< SECRET;

    std::string sighash(md5sum((char*)"%s", sig.str().c_str()));

    query << "&api_sig=" << sighash;

    OpenURL(GetServiceURL(), query.str().c_str());

    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	iprintf("%s", "Updated \"Now Playing\" status successfully.");
	retval = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	eprintf("%s%s", "Last.fm returned an error while updating the currently playing track:\n", _response.c_str());
	if(CheckFailure(_response))
	    Failure();
    }

    CLEANUP();
    return retval;
}

void CAudioScrobbler::Handshake()
{
    std::string username="";
    for(unsigned int i = 0; i < Config->getLUsername().length(); i++) {
	username.append(1, tolower(Config->getLUsername().c_str()[i]));
    }
    std::string authtoken(md5sum((char*)"%s%s", username.c_str(), Config->getLPassword().c_str()));

    std::ostringstream query, sig;
    query << "method=auth.getMobileSession&username=" << username << "&authToken=" << authtoken << "&api_key=" << APIKEY;

    sig << "api_key" << APIKEY << "authToken" << authtoken << "methodauth.getMobileSessionusername" << username << SECRET;
    std::string sighash(md5sum((char*)"%s", sig.str().c_str()));

    query << "&api_sig=" << sighash;

    OpenURL(GetServiceURL(), query.str().c_str());

    if(_response.find("<lfm status=\"ok\">") != std::string::npos) {
	size_t start, end;
	start = _response.find("<key>") + 5;
	end = _response.find("</key>");
	_sessionid = _response.substr(start, end-start);
	iprintf("%s%s", "Last.fm handshake successful. SessionID: ", _sessionid.c_str());
	_authed = true;
    }
    else if(_response.find("<lfm status=\"failed\">") != std::string::npos) {
	CheckFailure(_response);
	exit(EXIT_FAILURE);
    }

    CLEANUP();
}
<|endoftext|>


<commit_before>#include "modules.h"

#ifndef MODBASE_ROBOBO
#define MODBASE_ROBOBO
Module::Module() {}

Module::~Module() {}

void Module::init(ModuleInterface* modFace) {
	serverData = modFace;
}

void Module::onChannelMsg(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserMsg(std::string server, std::string nick, std::string message) {}

void Module::onChannelNotice(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserNotice(std::string server, std::string nick, std::string message) {}

void Module::onChannelCTCP(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserCTCP(std::string server, std::string nick, std::string message) {}

void Module::onChannelCTCPReply(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserCTCPReply(std::string server, std::string nick, std::string message) {}

void Module::onChannelJoin(std::string server, std::string channel, std::string hostmask) {}

void Module::onChannelPart(std::string server, std::string channel, std::string hostmask, std::string reason) {}

void Module::onUserQuit(std::string server, std::string hostmask, std::string reason) {}

void Module::onChannelKick(std::string server, std::string channel, std::string kicker, std::string kickee, std::string reason) {}

void Module::onChannelMode(std::string server, std::string channel, std::string setter, char mode, bool add, std::string param) {}

void Module::onNumeric(std::string server, std::string numeric, std::vector<std::string> parsedLine) {}

void Module::onOtherData(std::string server, std::vector<std::string> parsedLine) {}

void Module::onOutChannelMessage(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserMessage(std::string server, std::string target, std::string message) {}

void Module::onOutChannelNotice(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserNotice(std::string server, std::string target, std::string message) {}

void Module::onOutChannelCTCP(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserCTCP(std::string server, std::string target, std::string message) {}

void Module::onOutChannelCTCPReply(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserCTCPReply(std::string server, std::string target, std::string message) {}

void Module::sendPrivMsg(std::string server, std::string target, std::string message) {
	serverData->sendToServer(server, "PRIVMSG " + target + " :" + message);
}

void Module::sendNotice(std::string server, std::string target, std::string message) {
	serverData->sendToServer(server, "NOTICE " + target + " :" + message);
}

void Module::sendCTCP(std::string server, std::string target, std::string type, std::string params) {
	if (params == "")
		serverData->sendToServer(server, "PRIVMSG " + target + " :" + (char)1 + type + (char)1);
	else
		serverData->sendToServer(server, "PRIVMSG " + target + " :" + (char)1 + type + " " + params + (char)1);
}

void Module::sendCTCPReply(std::string server, std::string target, std::string type, std::string data) {
	if (data == "")
		serverData->sendToServer(server, "NOTICE " + target + " :" + (char)1 + type + (char)1);
	else
		serverData->sendToServer(server, "NOTICE " + target + " :" + (char)1 + type + " " + data + (char)1);
}

void Module::joinChannel(std::string server, std::string channel, std::string key) {
	serverData->sendToServer(server, "JOIN " + channel + " " + key);
}

void Module::partChannel(std::string server, std::string channel, std::string reason) {
	serverData->sendToServer(server, "PART " + channel + " :" + reason);
}

void Module::kickChannelUser(std::string server, std::string channel, std::string nick, std::string reason) {
	serverData->sendToServer(server, "KICK " + channel + " " + nick + " :" + reason);
}

void Module::setMode(std::string server, std::string channel, char mode, bool add, std::string param) {
	if (param == "") {
		if (add)
			serverData->sendToServer(server, "MODE " + channel + " +" + mode);
		else
			serverData->sendToServer(server, "MODE " + channel + " -" + mode);
	} else {
		if (add)
			serverData->sendToServer(server, "MODE " + channel + " +" + mode + " " + param);
		else
			serverData->sendToServer(server, "MODE " + channel + " -" + mode + " " + param);
	}
}

void Module::quitServer(std::string server, std::string reason) {
	serverData->sendToServer(server, "QUIT :" + reason);
}

std::vector<std::string> Module::splitHostmask(std::string hostmask) {
	std::vector<std::string> splitmask;
	int exclamationPoint = hostmask.find_first_of('!');
	int atSign = hostmask.find_first_of('@');
	splitmask.push_back(hostmask.substr(0, exclamationPoint));
	splitmask.push_back(hostmask.substr(exclamationPoint, atSign - exclamationPoint));
	splitmask.push_back(hostmask.substr(atSign));
	return splitmask;
}

std::vector<std::string> Module::splitBySpace(std::string line) {
	std::vector<std::string> split;
	std::string temp = "";
	for (unsigned int i = 0; i < line.size(); i++) {
		if (line[i] == ' ') {
			split.push_back(temp);
			temp = "";
		} else
			temp += line[i];
	}
	return split;
}

std::list<std::string> Module::getServers() {
	return serverData->getServers();
}

std::tr1::unordered_map<std::string, Module*> Module::getModules() {
	return serverData->getModules();
}
#endif<commit_msg>Fix splitBySpace() to add the last word when it doesn't end in a space.<commit_after>#include "modules.h"

#ifndef MODBASE_ROBOBO
#define MODBASE_ROBOBO
Module::Module() {}

Module::~Module() {}

void Module::init(ModuleInterface* modFace) {
	serverData = modFace;
}

void Module::onChannelMsg(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserMsg(std::string server, std::string nick, std::string message) {}

void Module::onChannelNotice(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserNotice(std::string server, std::string nick, std::string message) {}

void Module::onChannelCTCP(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserCTCP(std::string server, std::string nick, std::string message) {}

void Module::onChannelCTCPReply(std::string server, std::string channel, char target, std::string nick, std::string message) {}

void Module::onUserCTCPReply(std::string server, std::string nick, std::string message) {}

void Module::onChannelJoin(std::string server, std::string channel, std::string hostmask) {}

void Module::onChannelPart(std::string server, std::string channel, std::string hostmask, std::string reason) {}

void Module::onUserQuit(std::string server, std::string hostmask, std::string reason) {}

void Module::onChannelKick(std::string server, std::string channel, std::string kicker, std::string kickee, std::string reason) {}

void Module::onChannelMode(std::string server, std::string channel, std::string setter, char mode, bool add, std::string param) {}

void Module::onNumeric(std::string server, std::string numeric, std::vector<std::string> parsedLine) {}

void Module::onOtherData(std::string server, std::vector<std::string> parsedLine) {}

void Module::onOutChannelMessage(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserMessage(std::string server, std::string target, std::string message) {}

void Module::onOutChannelNotice(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserNotice(std::string server, std::string target, std::string message) {}

void Module::onOutChannelCTCP(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserCTCP(std::string server, std::string target, std::string message) {}

void Module::onOutChannelCTCPReply(std::string server, std::string target, char status, std::string message) {}

void Module::onOutUserCTCPReply(std::string server, std::string target, std::string message) {}

void Module::sendPrivMsg(std::string server, std::string target, std::string message) {
	serverData->sendToServer(server, "PRIVMSG " + target + " :" + message);
}

void Module::sendNotice(std::string server, std::string target, std::string message) {
	serverData->sendToServer(server, "NOTICE " + target + " :" + message);
}

void Module::sendCTCP(std::string server, std::string target, std::string type, std::string params) {
	if (params == "")
		serverData->sendToServer(server, "PRIVMSG " + target + " :" + (char)1 + type + (char)1);
	else
		serverData->sendToServer(server, "PRIVMSG " + target + " :" + (char)1 + type + " " + params + (char)1);
}

void Module::sendCTCPReply(std::string server, std::string target, std::string type, std::string data) {
	if (data == "")
		serverData->sendToServer(server, "NOTICE " + target + " :" + (char)1 + type + (char)1);
	else
		serverData->sendToServer(server, "NOTICE " + target + " :" + (char)1 + type + " " + data + (char)1);
}

void Module::joinChannel(std::string server, std::string channel, std::string key) {
	serverData->sendToServer(server, "JOIN " + channel + " " + key);
}

void Module::partChannel(std::string server, std::string channel, std::string reason) {
	serverData->sendToServer(server, "PART " + channel + " :" + reason);
}

void Module::kickChannelUser(std::string server, std::string channel, std::string nick, std::string reason) {
	serverData->sendToServer(server, "KICK " + channel + " " + nick + " :" + reason);
}

void Module::setMode(std::string server, std::string channel, char mode, bool add, std::string param) {
	if (param == "") {
		if (add)
			serverData->sendToServer(server, "MODE " + channel + " +" + mode);
		else
			serverData->sendToServer(server, "MODE " + channel + " -" + mode);
	} else {
		if (add)
			serverData->sendToServer(server, "MODE " + channel + " +" + mode + " " + param);
		else
			serverData->sendToServer(server, "MODE " + channel + " -" + mode + " " + param);
	}
}

void Module::quitServer(std::string server, std::string reason) {
	serverData->sendToServer(server, "QUIT :" + reason);
}

std::vector<std::string> Module::splitHostmask(std::string hostmask) {
	std::vector<std::string> splitmask;
	int exclamationPoint = hostmask.find_first_of('!');
	int atSign = hostmask.find_first_of('@');
	splitmask.push_back(hostmask.substr(0, exclamationPoint));
	splitmask.push_back(hostmask.substr(exclamationPoint, atSign - exclamationPoint));
	splitmask.push_back(hostmask.substr(atSign));
	return splitmask;
}

std::vector<std::string> Module::splitBySpace(std::string line) {
	std::vector<std::string> split;
	std::string temp = "";
	for (unsigned int i = 0; i < line.size(); i++) {
		if (line[i] == ' ') {
			split.push_back(temp);
			temp = "";
		} else
			temp += line[i];
	}
	if (temp != "")
		split.push_back(temp);
	return split;
}

std::list<std::string> Module::getServers() {
	return serverData->getServers();
}

std::tr1::unordered_map<std::string, Module*> Module::getModules() {
	return serverData->getModules();
}
#endif<|endoftext|>


<commit_before>#include "chainerx/routines/activation.h"

#include <cmath>
#include <numeric>
#include <utility>
#include <vector>

#include "chainerx/array.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/enum.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/macro.h"
#include "chainerx/routines/arithmetic.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/explog.h"
#include "chainerx/routines/hyperbolic.h"
#include "chainerx/routines/indexing.h"
#include "chainerx/routines/manipulation.h"
#include "chainerx/routines/misc.h"
#include "chainerx/routines/type_util.h"
#include "chainerx/scalar.h"
#include "chainerx/shape.h"

namespace chainerx {

namespace {

std::vector<Array> ExtractGates(Array x, int64_t n_splits, int64_t axis) {
    StackVector<int64_t, kMaxNdim> shape_vec;
    shape_vec.emplace_back(x.shape()[0]);
    if (axis == 1) {
        shape_vec.emplace_back(n_splits);
        shape_vec.emplace_back(static_cast<int64_t>(x.shape()[1] / n_splits));
    } else {
        shape_vec.emplace_back(static_cast<int64_t>(x.shape()[1] / n_splits));
        shape_vec.emplace_back(n_splits);
    }
    for (int64_t i = 2; i < x.ndim(); i++) {
        shape_vec.emplace_back(x.shape()[i]);
    }
    Shape shape{shape_vec};
    Array x_r = Reshape(x, shape);
    std::vector<Array> x_split = Split(x_r, n_splits, axis);
    return x_split;
}

}  // namespace

Array ClippedRelu(const Array& x, Scalar z) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    return Minimum(Maximum(0, x_cast), z);
}

Array CRelu(const Array& x, int8_t axis) {
    // TODO(aksub99): Optimize implementation to use a single memory allocation.
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    std::vector<Array> c{x_cast, Negative(x_cast)};
    Array concat = Concatenate(c, axis);
    return Relu(concat);
}

Array Elu(const Array& x, double alpha) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    // TODO(aksub99): Replace x > zero with x > 0 when operator > supports scalars.
    Array zero = Zeros({}, x_cast.dtype(), x_cast.device());
    return Where(x_cast > zero, x_cast, alpha * Expm1(x_cast));
}

Array Sigmoid(const Array& x) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    return Reciprocal(1 + Exp(-x_cast));
}

Array Relu(const Array& x) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    return Maximum(0, x_cast);
}

Array LeakyRelu(const Array& x, Scalar slope) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    // TODO(hamaji): Replace x >= zero with x >= 0 when operator >= supports scalars.
    Array zero = Zeros({}, x_cast.dtype(), x_cast.device());
    return Where(x_cast >= zero, x_cast, slope * x_cast);
}

std::vector<Array> SLstm(const Array& c_prev1, const Array& c_prev2, const Array& x1, const Array& x2) {
    std::vector<Array> x1_gates = ExtractGates(x1, 4, 2);
    std::vector<Array> x2_gates = ExtractGates(x2, 4, 2);
    Array a1 = Squeeze(x1_gates[0]);
    Array i1 = Squeeze(x1_gates[1]);
    Array f1 = Squeeze(x1_gates[2]);
    Array o1 = Squeeze(x1_gates[3]);

    Array a2 = Squeeze(x2_gates[0]);
    Array i2 = Squeeze(x2_gates[1]);
    Array f2 = Squeeze(x2_gates[2]);
    Array o2 = Squeeze(x2_gates[3]);

    a1 = Tanh(a1);
    i1 = Sigmoid(i1);
    f1 = Sigmoid(f1);

    a2 = Tanh(a2);
    i2 = Sigmoid(i2);
    f2 = Sigmoid(f2);

    Array o = Sigmoid(o1 + o2);
    Array c = a1 * i1 + a2 * i2 + f1 * c_prev1 + f2 * c_prev2;
    Array h = o * Tanh(c);

    return {c, h};
}

Array Softplus(const Array& x, double beta) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    double beta_inv = 1.0 / beta;
    Array bx = beta * x_cast;
    Array y = (Maximum(bx, 0) + Log1p(Exp(-Fabs(bx)))) * beta_inv;
    return y;
}

}  // namespace chainerx
<commit_msg>fix clang error<commit_after>#include "chainerx/routines/activation.h"

#include <cmath>
#include <numeric>
#include <utility>
#include <vector>

#include "chainerx/array.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/enum.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/macro.h"
#include "chainerx/routines/arithmetic.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/explog.h"
#include "chainerx/routines/hyperbolic.h"
#include "chainerx/routines/indexing.h"
#include "chainerx/routines/manipulation.h"
#include "chainerx/routines/misc.h"
#include "chainerx/routines/type_util.h"
#include "chainerx/scalar.h"
#include "chainerx/shape.h"

namespace chainerx {

namespace {

std::vector<Array> ExtractGates(const Array& x, int64_t n_splits, int64_t axis) {
    StackVector<int64_t, kMaxNdim> shape_vec;
    shape_vec.emplace_back(x.shape()[0]);
    if (axis == 1) {
        shape_vec.emplace_back(n_splits);
        shape_vec.emplace_back(static_cast<int64_t>(x.shape()[1] / n_splits));
    } else {
        shape_vec.emplace_back(static_cast<int64_t>(x.shape()[1] / n_splits));
        shape_vec.emplace_back(n_splits);
    }
    for (int64_t i = 2; i < x.ndim(); i++) {
        shape_vec.emplace_back(x.shape()[i]);
    }
    Shape shape{shape_vec};
    Array x_r = Reshape(x, shape);
    std::vector<Array> x_split = Split(x_r, n_splits, axis);
    return x_split;
}

}  // namespace

Array ClippedRelu(const Array& x, Scalar z) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    return Minimum(Maximum(0, x_cast), z);
}

Array CRelu(const Array& x, int8_t axis) {
    // TODO(aksub99): Optimize implementation to use a single memory allocation.
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    std::vector<Array> c{x_cast, Negative(x_cast)};
    Array concat = Concatenate(c, axis);
    return Relu(concat);
}

Array Elu(const Array& x, double alpha) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    // TODO(aksub99): Replace x > zero with x > 0 when operator > supports scalars.
    Array zero = Zeros({}, x_cast.dtype(), x_cast.device());
    return Where(x_cast > zero, x_cast, alpha * Expm1(x_cast));
}

Array Sigmoid(const Array& x) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    return Reciprocal(1 + Exp(-x_cast));
}

Array Relu(const Array& x) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    return Maximum(0, x_cast);
}

Array LeakyRelu(const Array& x, Scalar slope) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    // TODO(hamaji): Replace x >= zero with x >= 0 when operator >= supports scalars.
    Array zero = Zeros({}, x_cast.dtype(), x_cast.device());
    return Where(x_cast >= zero, x_cast, slope * x_cast);
}

std::vector<Array> SLstm(const Array& c_prev1, const Array& c_prev2, const Array& x1, const Array& x2) {
    std::vector<Array> x1_gates = ExtractGates(x1, 4, 2);
    std::vector<Array> x2_gates = ExtractGates(x2, 4, 2);
    Array a1 = Squeeze(x1_gates[0]);
    Array i1 = Squeeze(x1_gates[1]);
    Array f1 = Squeeze(x1_gates[2]);
    Array o1 = Squeeze(x1_gates[3]);

    Array a2 = Squeeze(x2_gates[0]);
    Array i2 = Squeeze(x2_gates[1]);
    Array f2 = Squeeze(x2_gates[2]);
    Array o2 = Squeeze(x2_gates[3]);

    a1 = Tanh(a1);
    i1 = Sigmoid(i1);
    f1 = Sigmoid(f1);

    a2 = Tanh(a2);
    i2 = Sigmoid(i2);
    f2 = Sigmoid(f2);

    Array o = Sigmoid(o1 + o2);
    Array c = a1 * i1 + a2 * i2 + f1 * c_prev1 + f2 * c_prev2;
    Array h = o * Tanh(c);

    return {c, h};
}

Array Softplus(const Array& x, double beta) {
    Dtype dtype = internal::GetMathResultDtype(x.dtype());
    const Array& x_cast = x.dtype() == dtype ? x : x.AsType(dtype);
    double beta_inv = 1.0 / beta;
    Array bx = beta * x_cast;
    Array y = (Maximum(bx, 0) + Log1p(Exp(-Fabs(bx)))) * beta_inv;
    return y;
}

}  // namespace chainerx
<|endoftext|>