<commit_before>#include "transactionview.h"

// Temp includes for filtering prototype
// Move to TransactionFilterRow class
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
#include "transactiontablemodel.h"
#include "guiutil.h"

#include <QScrollBar>
#include <QComboBox>
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTableView>
#include <QHeaderView>

#include <QDebug>

TransactionView::TransactionView(QWidget *parent) :
    QWidget(parent), model(0), transactionProxyModel(0),
    transactionView(0)
{
    // Build filter row
    QHBoxLayout *hlayout = new QHBoxLayout();
    hlayout->setContentsMargins(QMargins(0,0,0,0));
    hlayout->setSpacing(0);

    hlayout->addSpacing(23);

    dateWidget = new QComboBox(this);
    dateWidget->setMaximumWidth(120);
    dateWidget->setMinimumWidth(120);
    dateWidget->addItem(tr("All"), All);
    dateWidget->addItem(tr("Today"), Today);
    dateWidget->addItem(tr("This week"), ThisWeek);
    dateWidget->addItem(tr("This month"), ThisMonth);
    dateWidget->addItem(tr("Last month"), LastMonth);
    dateWidget->addItem(tr("This year"), ThisYear);
    dateWidget->addItem(tr("Range..."), Range);
    hlayout->addWidget(dateWidget);

    typeWidget = new QComboBox(this);
    typeWidget->setMaximumWidth(120);
    typeWidget->setMinimumWidth(120);

    typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
    typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
                                        TransactionFilterProxy::TYPE(TransactionRecord::RecvFromIP));
    typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
                                  TransactionFilterProxy::TYPE(TransactionRecord::SendToIP));
    typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
    typeWidget->addItem(tr("Generated"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
    typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));

    hlayout->addWidget(typeWidget);

    addressWidget = new QLineEdit(this);
    addressWidget->setPlaceholderText("Enter address or label to search");
    hlayout->addWidget(addressWidget);

    amountWidget = new QLineEdit(this);
    amountWidget->setPlaceholderText("Min amount");
    amountWidget->setMaximumWidth(100);
    amountWidget->setMinimumWidth(100);
    amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
    hlayout->addWidget(amountWidget);

    QVBoxLayout *vlayout = new QVBoxLayout(this);

    QTableView *view = new QTableView(this);
    vlayout->addLayout(hlayout);
    vlayout->addWidget(view);
    vlayout->setSpacing(0);
    int width = view->verticalScrollBar()->sizeHint().width();
    // Cover scroll bar width with spacing
    hlayout->addSpacing(width);
    // Always show scroll bar
    view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

    transactionView = view;

    connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
    connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
    connect(addressWidget, SIGNAL(textChanged(const QString&)), this, SLOT(changedPrefix(const QString&)));
    connect(amountWidget, SIGNAL(textChanged(const QString&)), this, SLOT(changedAmount(const QString&)));

    connect(view, SIGNAL(doubleClicked(const QModelIndex&)), this, SIGNAL(doubleClicked(const QModelIndex&)));
}

void TransactionView::setModel(TransactionTableModel *model)
{
    this->model = model;

    transactionProxyModel = new TransactionFilterProxy(this);
    transactionProxyModel->setSourceModel(model);
    transactionProxyModel->setDynamicSortFilter(true);

    transactionProxyModel->setSortRole(Qt::EditRole);

    transactionView->setModel(transactionProxyModel);
    transactionView->setAlternatingRowColors(true);
    transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
    transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    transactionView->setSortingEnabled(true);
    transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
    transactionView->verticalHeader()->hide();

    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Status, 23);
    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Date, 120);
    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Type, 120);
    transactionView->horizontalHeader()->setResizeMode(
            TransactionTableModel::ToAddress, QHeaderView::Stretch);
    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Amount, 100);

}

void TransactionView::chooseDate(int idx)
{
    QDate current = QDate::currentDate();
    switch(dateWidget->itemData(idx).toInt())
    {
    case All:
        transactionProxyModel->setDateRange(
                TransactionFilterProxy::MIN_DATE,
                TransactionFilterProxy::MAX_DATE);
        break;
    case Today:
        transactionProxyModel->setDateRange(
                QDateTime(current),
                TransactionFilterProxy::MAX_DATE);
        break;
    case ThisWeek: {
        // Find last monday
        QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
        transactionProxyModel->setDateRange(
                QDateTime(startOfWeek),
                TransactionFilterProxy::MAX_DATE);

        } break;
    case ThisMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month(), 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case LastMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month()-1, 1)),
                QDateTime(QDate(current.year(), current.month(), 1)));
        break;
    case ThisYear:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), 1, 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case Range:
        // TODO ask specific range
        break;
    }

}

void TransactionView::chooseType(int idx)
{
    transactionProxyModel->setTypeFilter(
        typeWidget->itemData(idx).toInt());
}

void TransactionView::changedPrefix(const QString &prefix)
{
    transactionProxyModel->setAddressPrefix(prefix);
}

void TransactionView::changedAmount(const QString &amount)
{
    qint64 amount_parsed = 0;
    if(GUIUtil::parseMoney(amount, &amount_parsed))
    {
        transactionProxyModel->setMinAmount(amount_parsed);
    }
    else
    {
        transactionProxyModel->setMinAmount(0);
    }
}
<commit_msg>Placeholder text can only be used for Qt 4.7+<commit_after>#include "transactionview.h"

// Temp includes for filtering prototype
// Move to TransactionFilterRow class
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
#include "transactiontablemodel.h"
#include "guiutil.h"

#include <QScrollBar>
#include <QComboBox>
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTableView>
#include <QHeaderView>

#include <QDebug>

TransactionView::TransactionView(QWidget *parent) :
    QWidget(parent), model(0), transactionProxyModel(0),
    transactionView(0)
{
    // Build filter row
    QHBoxLayout *hlayout = new QHBoxLayout();
    hlayout->setContentsMargins(QMargins(0,0,0,0));
    hlayout->setSpacing(0);

    hlayout->addSpacing(23);

    dateWidget = new QComboBox(this);
    dateWidget->setMaximumWidth(120);
    dateWidget->setMinimumWidth(120);
    dateWidget->addItem(tr("All"), All);
    dateWidget->addItem(tr("Today"), Today);
    dateWidget->addItem(tr("This week"), ThisWeek);
    dateWidget->addItem(tr("This month"), ThisMonth);
    dateWidget->addItem(tr("Last month"), LastMonth);
    dateWidget->addItem(tr("This year"), ThisYear);
    dateWidget->addItem(tr("Range..."), Range);
    hlayout->addWidget(dateWidget);

    typeWidget = new QComboBox(this);
    typeWidget->setMaximumWidth(120);
    typeWidget->setMinimumWidth(120);

    typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
    typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
                                        TransactionFilterProxy::TYPE(TransactionRecord::RecvFromIP));
    typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
                                  TransactionFilterProxy::TYPE(TransactionRecord::SendToIP));
    typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
    typeWidget->addItem(tr("Generated"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
    typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));

    hlayout->addWidget(typeWidget);

    addressWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
    addressWidget->setPlaceholderText("Enter address or label to search");
#endif
    hlayout->addWidget(addressWidget);

    amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
    amountWidget->setPlaceholderText("Min amount");
#endif
    amountWidget->setMaximumWidth(100);
    amountWidget->setMinimumWidth(100);
    amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
    hlayout->addWidget(amountWidget);

    QVBoxLayout *vlayout = new QVBoxLayout(this);

    QTableView *view = new QTableView(this);
    vlayout->addLayout(hlayout);
    vlayout->addWidget(view);
    vlayout->setSpacing(0);
    int width = view->verticalScrollBar()->sizeHint().width();
    // Cover scroll bar width with spacing
    hlayout->addSpacing(width);
    // Always show scroll bar
    view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

    transactionView = view;

    connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
    connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
    connect(addressWidget, SIGNAL(textChanged(const QString&)), this, SLOT(changedPrefix(const QString&)));
    connect(amountWidget, SIGNAL(textChanged(const QString&)), this, SLOT(changedAmount(const QString&)));

    connect(view, SIGNAL(doubleClicked(const QModelIndex&)), this, SIGNAL(doubleClicked(const QModelIndex&)));
}

void TransactionView::setModel(TransactionTableModel *model)
{
    this->model = model;

    transactionProxyModel = new TransactionFilterProxy(this);
    transactionProxyModel->setSourceModel(model);
    transactionProxyModel->setDynamicSortFilter(true);

    transactionProxyModel->setSortRole(Qt::EditRole);

    transactionView->setModel(transactionProxyModel);
    transactionView->setAlternatingRowColors(true);
    transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
    transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    transactionView->setSortingEnabled(true);
    transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
    transactionView->verticalHeader()->hide();

    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Status, 23);
    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Date, 120);
    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Type, 120);
    transactionView->horizontalHeader()->setResizeMode(
            TransactionTableModel::ToAddress, QHeaderView::Stretch);
    transactionView->horizontalHeader()->resizeSection(
            TransactionTableModel::Amount, 100);

}

void TransactionView::chooseDate(int idx)
{
    QDate current = QDate::currentDate();
    switch(dateWidget->itemData(idx).toInt())
    {
    case All:
        transactionProxyModel->setDateRange(
                TransactionFilterProxy::MIN_DATE,
                TransactionFilterProxy::MAX_DATE);
        break;
    case Today:
        transactionProxyModel->setDateRange(
                QDateTime(current),
                TransactionFilterProxy::MAX_DATE);
        break;
    case ThisWeek: {
        // Find last monday
        QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
        transactionProxyModel->setDateRange(
                QDateTime(startOfWeek),
                TransactionFilterProxy::MAX_DATE);

        } break;
    case ThisMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month(), 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case LastMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month()-1, 1)),
                QDateTime(QDate(current.year(), current.month(), 1)));
        break;
    case ThisYear:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), 1, 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case Range:
        // TODO ask specific range
        break;
    }

}

void TransactionView::chooseType(int idx)
{
    transactionProxyModel->setTypeFilter(
        typeWidget->itemData(idx).toInt());
}

void TransactionView::changedPrefix(const QString &prefix)
{
    transactionProxyModel->setAddressPrefix(prefix);
}

void TransactionView::changedAmount(const QString &amount)
{
    qint64 amount_parsed = 0;
    if(GUIUtil::parseMoney(amount, &amount_parsed))
    {
        transactionProxyModel->setMinAmount(amount_parsed);
    }
    else
    {
        transactionProxyModel->setMinAmount(0);
    }
}
<|endoftext|>


<commit_before>#include "rosplan_planning_system/PlannerInterface/FFPlannerInterface.h"

namespace KCL_rosplan {

	/*-------------*/
	/* constructor */
	/*-------------*/

	FFPlannerInterface::FFPlannerInterface(ros::NodeHandle& nh)
	{
		node_handle = &nh;

		plan_server = new actionlib::SimpleActionServer<rosplan_dispatch_msgs::PlanAction>((*node_handle), "start_planning", boost::bind(&PlannerInterface::runPlanningServerAction, this, _1), false);

		// publishing raw planner output
		std::string plannerTopic = "planner_output";
		node_handle->getParam("planner_topic", plannerTopic);
		plan_publisher = node_handle->advertise<std_msgs::String>(plannerTopic, 1, true);

		node_handle->param<bool>("use_ffha", this->use_ffha, false);

		// start planning action server
		plan_server->start();
	}

	FFPlannerInterface::~FFPlannerInterface()
	{
		delete plan_server;
	}

	/**
	 * Runs external commands
	 */
	std::string FFPlannerInterface::runCommand(std::string cmd) {
		std::string data;
		FILE *stream;
		char buffer[1000];
		stream = popen(cmd.c_str(), "r");
		while ( fgets(buffer, 1000, stream) != NULL )
			data.append(buffer);
		pclose(stream);
		return data;
	}

	/*------------------*/
	/* Plan and process */
	/*------------------*/

	/**
	 * passes the problem to the Planner; the plan to post-processing.
	 */
	bool FFPlannerInterface::runPlanner() {
		planner_output.clear(); // Clear previous plan
		// save problem to file for planner
		if(use_problem_topic && problem_instance_received) {
			ROS_INFO("KCL: (%s) (%s) Writing problem to file.", ros::this_node::getName().c_str(), problem_name.c_str());
			std::ofstream dest;
			dest.open((problem_path).c_str());
			dest << problem_instance;
			dest.close();
		}

		// prepare the planner command line
		std::string str = planner_command;
		std::size_t dit = str.find("DOMAIN");
		if(dit!=std::string::npos) str.replace(dit,6,domain_path);
		std::size_t pit = str.find("PROBLEM");
		if(pit!=std::string::npos) str.replace(pit,7,problem_path);
		std::string commandString = str + " > " + data_path + "plan.pddl";

		// call the planer
		ROS_INFO("KCL: (%s) (%s) Running: %s", ros::this_node::getName().c_str(), problem_name.c_str(),  commandString.c_str());
		std::string plan = runCommand(commandString.c_str());
		ROS_INFO("KCL: (%s) (%s) Planning complete", ros::this_node::getName().c_str(), problem_name.c_str());

		// check the planner solved the problem
		std::ifstream planfile;
		planfile.open((data_path + "plan.pddl").c_str());
		std::string line;

		bool solved = false;
		while (not solved and std::getline(planfile, line)) {
			// skip lines until there is a plan
			if (line.find("ff: found legal plan") != line.npos) {
				solved = true;
			}
		}

		// Parse the solved plan
		if (solved) {
			if (this->use_ffha)
			{
				std::getline(planfile, line); //go to first action line
			} else {
			// actions look like this:
			// step    0: got_place C1
			//         1: find_object V1 C1
			// plan cost: XX
				while (std::getline(planfile, line)) { // Move to the beginning of the plan
					if (line.substr(0, 4) == "step") {
						line = line.substr(4); // Remove the step
						break;
					}
				}
			}

			// First iteration line will be like   0: got_place C1
			while (line.find("Total cost") == line.npos and line.find("time spend") == line.npos and line.size() > 0) {
				std::stringstream ss(line); // To trim whitespaces
				std::string aux;
				// Read the action number X:
				ss >> aux;
				std::string add = (use_ffha) ? " " : " (";
				planner_output += aux + add; // Add parenthesis before the action
				while (ss >> aux) { // Read the rest
					planner_output += aux;
					if (ss.good()) planner_output += " "; // Add a whitespace unless we have processed all the line
				}
				add = (use_ffha) ? "  [0.001]\n" : ")  [0.001]\n";
				planner_output += add; // Close parenthesis and add duration
				std::getline(planfile, line);
			}
			// Convert to lowercase as FF prints all the actions and parameters in uppercase
			std::transform(planner_output.begin(), planner_output.end(), planner_output.begin(), ::tolower);
		}
		planfile.close();

		if(!solved) ROS_INFO("KCL: (%s) (%s) Plan was unsolvable.", ros::this_node::getName().c_str(), problem_name.c_str());
		else ROS_INFO("KCL: (%s) (%s) Plan was solved.", ros::this_node::getName().c_str(), problem_name.c_str());

		return solved;
	}

} // close namespace

	/*-------------*/
	/* Main method */
	/*-------------*/

	int main(int argc, char **argv) {

		srand (static_cast <unsigned> (time(0)));

		ros::init(argc,argv,"rosplan_planner_interface");
		ros::NodeHandle nh("~");

		KCL_rosplan::FFPlannerInterface pi(nh);

		// subscribe to problem instance
		std::string problemTopic = "problem_instance";
		nh.getParam("problem_topic", problemTopic);
		ros::Subscriber problem_sub = nh.subscribe(problemTopic, 1, &KCL_rosplan::PlannerInterface::problemCallback, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		// start the planning services
		ros::ServiceServer service1 = nh.advertiseService("planning_server", &KCL_rosplan::PlannerInterface::runPlanningServerDefault, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));
		ros::ServiceServer service2 = nh.advertiseService("planning_server_params", &KCL_rosplan::PlannerInterface::runPlanningServerParams, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		ROS_INFO("KCL: (%s) Ready to receive", ros::this_node::getName().c_str());
		ros::spin();

		return 0;
	}
<commit_msg>Update FFPlannerInterface.cpp<commit_after>#include "rosplan_planning_system/PlannerInterface/FFPlannerInterface.h"

namespace KCL_rosplan {

	/*-------------*/
	/* constructor */
	/*-------------*/

	FFPlannerInterface::FFPlannerInterface(ros::NodeHandle& nh)
	{
		node_handle = &nh;

		plan_server = new actionlib::SimpleActionServer<rosplan_dispatch_msgs::PlanAction>((*node_handle), "start_planning", boost::bind(&PlannerInterface::runPlanningServerAction, this, _1), false);

		// publishing raw planner output
		std::string plannerTopic = "planner_output";
		node_handle->getParam("planner_topic", plannerTopic);
		plan_publisher = node_handle->advertise<std_msgs::String>(plannerTopic, 1, true);

		node_handle->param<bool>("use_ffha", this->use_ffha, false);

		// start planning action server
		plan_server->start();
	}

	FFPlannerInterface::~FFPlannerInterface()
	{
		delete plan_server;
	}

	/**
	 * Runs external commands
	 */
	std::string FFPlannerInterface::runCommand(std::string cmd) {
		std::string data;
		FILE *stream;
		char buffer[1000];
		stream = popen(cmd.c_str(), "r");
		while ( fgets(buffer, 1000, stream) != NULL )
			data.append(buffer);
		pclose(stream);
		return data;
	}

	/*------------------*/
	/* Plan and process */
	/*------------------*/

	/**
	 * passes the problem to the Planner; the plan to post-processing.
	 */
	bool FFPlannerInterface::runPlanner() {
		planner_output.clear(); // Clear previous plan
		// save problem to file for planner
		if(use_problem_topic && problem_instance_received) {
			ROS_INFO("KCL: (%s) (%s) Writing problem to file.", ros::this_node::getName().c_str(), problem_name.c_str());
			std::ofstream dest;
			dest.open((problem_path).c_str());
			dest << problem_instance;
			dest.close();
		}

		// prepare the planner command line
		std::string str = planner_command;
		std::size_t dit = str.find("DOMAIN");
		if(dit!=std::string::npos) str.replace(dit,6,domain_path);
		std::size_t pit = str.find("PROBLEM");
		if(pit!=std::string::npos) str.replace(pit,7,problem_path);
		std::string commandString = str + " > " + data_path + "plan.pddl";

		// call the planer
		ROS_INFO("KCL: (%s) (%s) Running: %s", ros::this_node::getName().c_str(), problem_name.c_str(),  commandString.c_str());
		std::string plan = runCommand(commandString.c_str());
		ROS_INFO("KCL: (%s) (%s) Planning complete", ros::this_node::getName().c_str(), problem_name.c_str());

		// check the planner solved the problem
		std::ifstream planfile;
		planfile.open((data_path + "plan.pddl").c_str());
		std::string line;

		bool solved = false;
		while (not solved and std::getline(planfile, line)) {
			// skip lines until there is a plan
			if (line.find("ff: found legal plan") != line.npos) {
				solved = true;
			}
		}

		// Parse the solved plan
		if (solved) {
			if (this->use_ffha)
			{
				std::getline(planfile, line); //go to first action line
			} else {
			// actions look like this:
			// step    0: got_place C1
			//         1: find_object V1 C1
			// plan cost: XX
				while (std::getline(planfile, line)) { // Move to the beginning of the plan
					if (line.substr(0, 4) == "step") {
						line = line.substr(4); // Remove the step
						break;
					}
				}
			}

			// First iteration line will be like   0: got_place C1
			while (line.find("plan cost") == line.npos and line.find("Total cost") == line.npos and line.find("time spend") == line.npos and line.size() > 0) {
				std::stringstream ss(line); // To trim whitespaces
				std::string aux;
				// Read the action number X:
				ss >> aux;
				std::string add = (use_ffha) ? " " : " (";
				planner_output += aux + add; // Add parenthesis before the action
				while (ss >> aux) { // Read the rest
					planner_output += aux;
					if (ss.good()) planner_output += " "; // Add a whitespace unless we have processed all the line
				}
				add = (use_ffha) ? "  [0.001]\n" : ")  [0.001]\n";
				planner_output += add; // Close parenthesis and add duration
				std::getline(planfile, line);
			}
			// Convert to lowercase as FF prints all the actions and parameters in uppercase
			std::transform(planner_output.begin(), planner_output.end(), planner_output.begin(), ::tolower);
		}
		planfile.close();

		if(!solved) ROS_INFO("KCL: (%s) (%s) Plan was unsolvable.", ros::this_node::getName().c_str(), problem_name.c_str());
		else ROS_INFO("KCL: (%s) (%s) Plan was solved.", ros::this_node::getName().c_str(), problem_name.c_str());

		return solved;
	}

} // close namespace

	/*-------------*/
	/* Main method */
	/*-------------*/

	int main(int argc, char **argv) {

		srand (static_cast <unsigned> (time(0)));

		ros::init(argc,argv,"rosplan_planner_interface");
		ros::NodeHandle nh("~");

		KCL_rosplan::FFPlannerInterface pi(nh);

		// subscribe to problem instance
		std::string problemTopic = "problem_instance";
		nh.getParam("problem_topic", problemTopic);
		ros::Subscriber problem_sub = nh.subscribe(problemTopic, 1, &KCL_rosplan::PlannerInterface::problemCallback, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		// start the planning services
		ros::ServiceServer service1 = nh.advertiseService("planning_server", &KCL_rosplan::PlannerInterface::runPlanningServerDefault, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));
		ros::ServiceServer service2 = nh.advertiseService("planning_server_params", &KCL_rosplan::PlannerInterface::runPlanningServerParams, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		ROS_INFO("KCL: (%s) Ready to receive", ros::this_node::getName().c_str());
		ros::spin();

		return 0;
	}
<|endoftext|>


<commit_before>#include "static.h"
#include "page.h"
#include "../render.h"

using namespace Render;

void Html::quickStart(){
    header("Thanks");
    o << "
Now that you've registered you can upload your tracks and follow artists: just click your name at the top right corner of the page.
"
         "
Don't submit any tracks but your own, though.
";
    footer();
}

void Html::faq(){
    header("FAQ");
    o << "
Frequently Asked Questions

"

        "
General
"

        "

What is this?
"
        "
A place for artists to publish their MLP-related music, and get in touch with their audience.

"

        "

Why?
"
        "
Because there is no other central repository for MLP music.

"

        "

Why not [INSERT SITE HERE]?
"
        "
Because we try to make the publishing and listening process as smooth as can be. No ads, no limits, no downsides.

"

        "

So how do I get on the list of artists? I wanna be one of the cool kids!
"
        "
Sign up for an account. Log in, get to your user page, and upload a track, then publish it. Voilà, you're on the list.

"

        "
YouTube
"

        "
Why would I want to link my YouTube account to my EqBeats account?
"
        "
When your YouTube account is linked, by the click of a button, we'll create a video out of your track and its cover art, upload it to your YouTube channel, and stick a direct download link in the description. "
        "Basically it allows you to reach both your YouTube audience and your audience here in a single upload.
"

        "
How do I link my YouTube account?
"
        "
Look for a button on your account edition page, as well as any of your tracks. Google will ask you to verify that you trust us. Then, you're done!
"

        "
How do I unlink my YouTube account?
"
        "
There is a button on your account edition page.
"

        "
Technical stuff
"

        "
What quality or bitrate are the audio files on EqBeats?
"
        "
OGG Vorbis files are ~128kbps.
"
        "
We do not re-encode MP3 files, we only update the title and artist tags. This means they are exactly the same quality as the artist's original MP3 file.
"
        "
Your browser will stream either depending on its capabilities. "
        "As of today (April 19 2012), Firefox will only play OGG, Chrome can play either and will prefer OGG, and Safari and IE will only play MP3.
"
        "
And before you ask, the cover art files are left untouched as well. We just make a few thumbnails.
"

        "
Do you have an API?
"
        "
We do.
"

        "
Contact
"

        "

Who are you anyway?
"
        "
We're two developers: codl and fmang. For more information check the credits.

"

        "

I've got a question/problem/idea!
"
        "
What are you waiting for? Drop us a line at contact@eqbeats.org.
"
        "
Or come chat with us in <tt>#eqbeats</tt> on <tt>irc.ponychat.net</tt>. Don't be shy, we're friendly!

"

        "
";
    footer();
}

void Html::credits(){
    header("Credits");
    o << "
Credits

"
        "
Staff
"
        "
"
            "
codl
"
            "
fmang
"
        "
"
        "
Support
"
        "
"
            "
AspectOfTheStorm
"
            "
Makkon
"
            "
Karai
"
        "
"
        "
Design
"
        "
"
            "
SLT - Logo
"
            "
BlackM3sh - Filly Rarity
"
            "
Yusuke Kamiyamane - Fugue icon set
"
        "

";
    footer();
}

void Html::apiDoc(){
    header("API");
    o << "
"
         "
API
"
         "
Quickstart
"
         "
We have a read-only JSON/JSONP api to access user and track data.
"
         "Just add <tt>/json</tt> to most urls to get a JSON representation of that page.
"
         "Adding a <tt>jsonp</tt> parameter will insert the JSON data as an argument to a function named by the <tt>jsonp</tt> parameter. It can then be run by loading it in a <script> tag. More info on JSONP.
"
         "Compare /tracks/latest/json and /tracks/latest/json?jsonp=myCallback.
"
         "
User object
"
         "
"
            "
<tt>id</tt>	Unique numerical id for this user.
"
            "
<tt>name</tt>	User name.
"
            "
<tt>description</tt>	User's description of themselves, raw. This member will not exist if there is no description.
"
            "
<tt>html_description</tt>	Same as above, formatted to HTML.
"
            "
<tt>tracks</tt>	An array of Track objects for all tracks published by the user.
"
            "
<tt>playlists</tt>	Array of Playlist objects (id, name, author and link only).
"
            "
<tt>link</tt>	Permalink to the user's page.
"
         "
"
         "
{
"
         "  \"id\": 123,
"
         "  \"name\": \"Foo Bar\",
"
         "  \"description\": \"Just some dude making [b]music[/b].\",
"
         "  \"html_description\": \"Just some dude making <b>music</b>.\",
"
         "  \"tracks\": [{\"id\": 456, ...}, ...],
"
         "  \"playlists\": [{\"id\": 789, ...}, ...],
"
         "  \"link\": \"http://eqbeats.org/user/123\"
"
         "}
"
         "
Track object
"
         "
"
            "
<tt>id</tt>	Unique numerical id for the track.
"
            "
<tt>title</tt>	Track title.
"
            "
<tt>description</tt>	Track notes, raw. This member will not exist if there are no notes.
"
            "
<tt>html_description</tt>	Same as above, formatted to HTML.
"
            "
<tt>artist</tt>	A user object for the artist (excluding the track array).
"
            "
<tt>link</tt>	Permalink to the track's page.
"
            "
<tt>download</tt>	Permalinks to the downloadable / streamable audio files.
"
         "
"
         "
{
"
         "  \"id\": 456,
"
         "  \"title\": \"Baz Quux\",
"
         "  \"description\": \"A track about bazing while you quux.\",
"
         "  \"html_description\": \"A track about bazing while you quux.\",
"
         "  \"artist\": {\"id\": 123, \"name\": \"Foo Bar\",...}
"
         "  \"link\": \"http://eqbeats.org/track/456\",
"
         "  \"download\": {\"mp3\":\"http://eqbeats.org/track/456/mp3\",
"
         "               \"vorbis\":\"http://eqbeats.org/track/456/vorbis\"}
"
         "}
"
         "
Playlist object
"
         "
"
            "
<tt>id</tt>	Unique numerical id for the playlist.
"
            "
<tt>name</tt>	Playlist name.
"
            "
<tt>description</tt>	Description, raw. This member will not exist if there is no description.
"
            "
<tt>html_description</tt>	Same as above, formatted to HTML.
"
            "
<tt>author</tt>	A user object for the author.
"
            "
<tt>tracks</tt>	An array of Track objects.
"
            "
<tt>link</tt>	Permalink to the playlist's page.
"
         "
"
         "
Resources
"
         "
"
         "
<tt>/user/<var>{id}</var>/json</tt>	One user object.
"
         "
<tt>/users/search/json?q=<var>{query}</var></tt>	[Array] User objects matching the query.
"
         "
<tt>/user/<var>{id}</var>/favorites/json</tt>	[Array] Favorite tracks.
"
         "
<tt>/artists/json</tt>	[Array] All artists (as shortened user objects, without their tracks).
"
         "
<tt>/track/<var>{id}</var>/json</tt>	One track object.
"
         "
<tt>/tracks/search/json?q=<var>{query}</var></tt>	[Array] Track objects matching the query.
"
         "
<tt>/tracks/search/exact/json?artist=<var>{artist}</var>&track=<var>{track}</var></tt>	[Array] Track object matching the artist and track name exactly (case sensitive).
"
         "
<tt>/tracks/latest/json</tt>	[Array] The latest 50 tracks.
"
         "
<tt>/tracks/featured/json</tt>	[Array] The latest 50 featured tracks.
"
         "
<tt>/tracks/random/json</tt>	[Array] 50 random tracks.
"
         "
<tt>/playlist/<var>{id}</var>/json</tt>	One playlist object.
"
         "
"
         "
"
         ;
    footer();
}
<commit_msg>gravatar FAQ entry<commit_after>#include "static.h"
#include "page.h"
#include "../render.h"

using namespace Render;

void Html::quickStart(){
    header("Thanks");
    o << "
Now that you've registered you can upload your tracks and follow artists: just click your name at the top right corner of the page.
"
         "
Don't submit any tracks but your own, though.
";
    footer();
}

void Html::faq(){
    header("FAQ");
    o << "
Frequently Asked Questions

"

        "
General
"

        "

What is this?
"
        "
A place for artists to publish their MLP-related music, and get in touch with their audience.

"

        "

Why?
"
        "
Because there is no other central repository for MLP music.

"

        "

Why not [INSERT SITE HERE]?
"
        "
Because we try to make the publishing and listening process as smooth as can be. No ads, no limits, no downsides.

"

        "

So how do I get on the list of artists? I wanna be one of the cool kids!
"
        "
Sign up for an account. Log in, get to your user page, and upload a track, then publish it. Voilà, you're on the list.

"

        "
How do I set my avatar up?
"
        "
Go to Gravatar.com and create an account with the same email address as here. Upload your avatar there, it will show up here, and on other gravatar-enabled sites.
"

        "
YouTube
"

        "
Why would I want to link my YouTube account to my EqBeats account?
"
        "
When your YouTube account is linked, by the click of a button, we'll create a video out of your track and its cover art, upload it to your YouTube channel, and stick a direct download link in the description. "
        "Basically it allows you to reach both your YouTube audience and your audience here in a single upload.
"

        "
How do I link my YouTube account?
"
        "
Look for a button on your account edition page, as well as any of your tracks. Google will ask you to verify that you trust us. Then, you're done!
"

        "
How do I unlink my YouTube account?
"
        "
There is a button on your account edition page.
"

        "
Technical stuff
"

        "
What quality or bitrate are the audio files on EqBeats?
"
        "
OGG Vorbis files are ~128kbps.
"
        "
We do not re-encode MP3 files, we only update the title and artist tags. This means they are exactly the same quality as the artist's original MP3 file.
"
        "
Your browser will stream either depending on its capabilities. "
        "As of today (April 19 2012), Firefox will only play OGG, Chrome can play either and will prefer OGG, and Safari and IE will only play MP3.
"
        "
And before you ask, the cover art files are left untouched as well. We just make a few thumbnails.
"

        "
Do you have an API?
"
        "
We do.
"

        "
Contact
"

        "

Who are you anyway?
"
        "
We're two developers: codl and fmang. For more information check the credits.

"

        "

I've got a question/problem/idea!
"
        "
What are you waiting for? Drop us a line at contact@eqbeats.org.
"
        "
Or come chat with us in <tt>#eqbeats</tt> on <tt>irc.ponychat.net</tt>. Don't be shy, we're friendly!

"

        "
";
    footer();
}

void Html::credits(){
    header("Credits");
    o << "
Credits

"
        "
Staff
"
        "
"
            "
codl
"
            "
fmang
"
        "
"
        "
Support
"
        "
"
            "
AspectOfTheStorm
"
            "
Makkon
"
            "
Karai
"
        "
"
        "
Design
"
        "
"
            "
SLT - Logo
"
            "
BlackM3sh - Filly Rarity
"
            "
Yusuke Kamiyamane - Fugue icon set
"
        "

";
    footer();
}

void Html::apiDoc(){
    header("API");
    o << "
"
         "
API
"
         "
Quickstart
"
         "
We have a read-only JSON/JSONP api to access user and track data.
"
         "Just add <tt>/json</tt> to most urls to get a JSON representation of that page.
"
         "Adding a <tt>jsonp</tt> parameter will insert the JSON data as an argument to a function named by the <tt>jsonp</tt> parameter. It can then be run by loading it in a <script> tag. More info on JSONP.
"
         "Compare /tracks/latest/json and /tracks/latest/json?jsonp=myCallback.
"
         "
User object
"
         "
"
            "
<tt>id</tt>	Unique numerical id for this user.
"
            "
<tt>name</tt>	User name.
"
            "
<tt>description</tt>	User's description of themselves, raw. This member will not exist if there is no description.
"
            "
<tt>html_description</tt>	Same as above, formatted to HTML.
"
            "
<tt>tracks</tt>	An array of Track objects for all tracks published by the user.
"
            "
<tt>playlists</tt>	Array of Playlist objects (id, name, author and link only).
"
            "
<tt>link</tt>	Permalink to the user's page.
"
         "
"
         "
{
"
         "  \"id\": 123,
"
         "  \"name\": \"Foo Bar\",
"
         "  \"description\": \"Just some dude making [b]music[/b].\",
"
         "  \"html_description\": \"Just some dude making <b>music</b>.\",
"
         "  \"tracks\": [{\"id\": 456, ...}, ...],
"
         "  \"playlists\": [{\"id\": 789, ...}, ...],
"
         "  \"link\": \"http://eqbeats.org/user/123\"
"
         "}
"
         "
Track object
"
         "
"
            "
<tt>id</tt>	Unique numerical id for the track.
"
            "
<tt>title</tt>	Track title.
"
            "
<tt>description</tt>	Track notes, raw. This member will not exist if there are no notes.
"
            "
<tt>html_description</tt>	Same as above, formatted to HTML.
"
            "
<tt>artist</tt>	A user object for the artist (excluding the track array).
"
            "
<tt>link</tt>	Permalink to the track's page.
"
            "
<tt>download</tt>	Permalinks to the downloadable / streamable audio files.
"
         "
"
         "
{
"
         "  \"id\": 456,
"
         "  \"title\": \"Baz Quux\",
"
         "  \"description\": \"A track about bazing while you quux.\",
"
         "  \"html_description\": \"A track about bazing while you quux.\",
"
         "  \"artist\": {\"id\": 123, \"name\": \"Foo Bar\",...}
"
         "  \"link\": \"http://eqbeats.org/track/456\",
"
         "  \"download\": {\"mp3\":\"http://eqbeats.org/track/456/mp3\",
"
         "               \"vorbis\":\"http://eqbeats.org/track/456/vorbis\"}
"
         "}
"
         "
Playlist object
"
         "
"
            "
<tt>id</tt>	Unique numerical id for the playlist.
"
            "
<tt>name</tt>	Playlist name.
"
            "
<tt>description</tt>	Description, raw. This member will not exist if there is no description.
"
            "
<tt>html_description</tt>	Same as above, formatted to HTML.
"
            "
<tt>author</tt>	A user object for the author.
"
            "
<tt>tracks</tt>	An array of Track objects.
"
            "
<tt>link</tt>	Permalink to the playlist's page.
"
         "
"
         "
Resources
"
         "
"
         "
<tt>/user/<var>{id}</var>/json</tt>	One user object.
"
         "
<tt>/users/search/json?q=<var>{query}</var></tt>	[Array] User objects matching the query.
"
         "
<tt>/user/<var>{id}</var>/favorites/json</tt>	[Array] Favorite tracks.
"
         "
<tt>/artists/json</tt>	[Array] All artists (as shortened user objects, without their tracks).
"
         "
<tt>/track/<var>{id}</var>/json</tt>	One track object.
"
         "
<tt>/tracks/search/json?q=<var>{query}</var></tt>	[Array] Track objects matching the query.
"
         "
<tt>/tracks/search/exact/json?artist=<var>{artist}</var>&track=<var>{track}</var></tt>	[Array] Track object matching the artist and track name exactly (case sensitive).
"
         "
<tt>/tracks/latest/json</tt>	[Array] The latest 50 tracks.
"
         "
<tt>/tracks/featured/json</tt>	[Array] The latest 50 featured tracks.
"
         "
<tt>/tracks/random/json</tt>	[Array] 50 random tracks.
"
         "
<tt>/playlist/<var>{id}</var>/json</tt>	One playlist object.
"
         "
"
         "
"
         ;
    footer();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2014 Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <exception>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <amxprof/call_graph_writer_dot.h>
#include <amxprof/function.h>
#include <amxprof/function_statistics.h>
#include <amxprof/statistics_writer_html.h>
#include <amxprof/statistics_writer_json.h>
#include <amxprof/statistics_writer_text.h>
#include "amxpath.h"
#include "fileutils.h"
#include "logprintf.h"
#include "profiler.h"

#define logprintf Use_Printf_isntead_of_logprintf

namespace {
namespace cfg {

ConfigReader server_cfg("server.cfg");

std::string gamemodes =
    server_cfg.GetValueWithDefault("profiler_gamemodes");
std::vector<std::string> filterscripts =
    server_cfg.GetValues<std::string>("profiler_filterscripts");
std::string output_format =
    server_cfg.GetValueWithDefault("profiler_outputformat", "html");
bool call_graph =
    server_cfg.GetValueWithDefault("profiler_callgraph", false);
std::string call_graph_format =
    server_cfg.GetValueWithDefault("profiler_callgraphformat", "dot");

namespace old {

// old config variables.
bool profile_gamemode =
    server_cfg.GetValueWithDefault("profile_gamemode", false);
std::vector<std::string> profile_filterscripts =
    server_cfg.GetValues<std::string>("profile_filterscripts");
std::string profile_format =
    server_cfg.GetValueWithDefault("profile_format", "html");
bool call_graph =
    server_cfg.GetValueWithDefault("call_graph", false);
std::string call_graph_format =
    server_cfg.GetValueWithDefault("call_graph_format", "dot");

} // namespace old
} // namespace cfg

void Printf(const char *format, ...) {
  std::va_list va;
  va_start(va, format);

  std::string new_format;
  new_format.append("[profiler] ");
  new_format.append(format);

  vlogprintf(new_format.c_str(), va);
  va_end(va);
}

void PrintException(const std::exception &e) {
  Printf("Error: %s", e.what());
}

void SplitString(const std::string &s,
                 char delim,
                 std::vector<std::string> &comps) {
  std::string::size_type begin = 0;
  std::string::size_type end;

  while (begin < s.length()) {
    end = s.find(delim, begin);
    end = (end == std::string::npos) ? s.length() : end;
    comps.push_back(std::string(s.begin() + begin, s.begin() + end));
    begin = end + 1;
  }
}

void ToLower(std::string &s) {
  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

std::string ToUnixPath(std::string path) {
  std::replace(path.begin(), path.end(), '\\', '/');
  return path;
}

bool IsCallGraphEnabled() {
  return cfg::call_graph || cfg::old::call_graph;
}

bool IsGameMode(const std::string &amx_path) {
  return amx_path.find("gamemodes/") != std::string::npos;
}

bool IsFilterScript(const std::string &amx_path) {
  return amx_path.find("filterscripts/") != std::string::npos;
}

bool ShouldBeProfiled(const std::string amx_path) {
  if (IsGameMode(amx_path)) {
    if (cfg::old::profile_gamemode) {
      return true;
    }
    std::vector<std::string> gm_names;
    SplitString(cfg::gamemodes, ' ', gm_names);
    for (std::vector<std::string>::const_iterator iterator = gm_names.begin();
         iterator != gm_names.end(); ++iterator) {
      const std::string &gm_name = *iterator;
      if (fileutils::SameFile(amx_path, "gamemodes/" + gm_name + ".amx") ||
          fileutils::SameFile(amx_path, "gamemodes/" + gm_name)) {
        return true;
      }
    }
  }
  if (IsFilterScript(amx_path)) {
    std::vector<std::string> fs_names;
    std::copy(cfg::old::profile_filterscripts.begin(),
              cfg::old::profile_filterscripts.end(),
              std::back_inserter(fs_names));
    std::copy(cfg::filterscripts.begin(),
              cfg::filterscripts.end(),
              std::back_inserter(fs_names));
    for (std::vector<std::string>::const_iterator iterator = fs_names.begin();
         iterator != fs_names.end(); ++iterator) {
      const std::string &fs_name = *iterator;
      if (fileutils::SameFile(amx_path, "filterscripts/" + fs_name + ".amx") ||
          fileutils::SameFile(amx_path, "filterscripts/" + fs_name)) {
        return true;
      }
    }
  }
  return false;
}

} // anonymous namespace

Profiler::Profiler(AMX *amx)
 : AMXService<Profiler>(amx),
   prev_debug_(amx->debug),
   prev_callback_(amx->callback),
   profiler_(amx, IsCallGraphEnabled()),
   state_(PROFILER_DISABLED)
{
  AmxPathFinder amx_path_finder;
  amx_path_finder.AddSearchDirectory("gamemodes");
  amx_path_finder.AddSearchDirectory("filterscripts");

  const char *amx_search_path = getenv("AMX_PATH");
  if (amx_search_path != 0) {
    std::vector<std::string> dirs;
    SplitString(amx_search_path, fileutils::kNativePathListSepChar, dirs);
    for (std::vector<std::string>::const_iterator iterator = dirs.begin();
         iterator != dirs.end(); ++iterator) {
      amx_path_finder.AddSearchDirectory(*iterator);
    }
  }

  amx_path_ = ToUnixPath(amx_path_finder.FindAmxPath(amx));
  amx_name_ = fileutils::GetDirectory(amx_path_)
            + "/"
            + fileutils::GetBaseName(amx_path_);

  if (amx_path_.empty()) {
    Printf("Could not find AMX file (try setting AMX_PATH?)");
  }
}

int Profiler::Load() {
  if (ShouldBeProfiled(amx_path_)) {
    Attach();
  }
  return AMX_ERR_NONE;
}

int Profiler::Unload() {
  return AMX_ERR_NONE;
}

int Profiler::Debug() {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.DebugHook(prev_debug_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  if (prev_debug_ != 0) {
    return prev_debug_(amx());
  }
  return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.CallbackHook(index, result, params, prev_callback_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return prev_callback_(amx(), index, result, params);
}

int Profiler::Exec(cell *retval, int index) {
  if (profiler_.call_stack()->is_empty()) {
    switch (state_) {
      case PROFILER_ATTACHING:
        if (!Attach()) {
          break;
        }
        // fallthrough
      case PROFILER_STARTING:
        CompleteStart();
        break;
    }
  }
  if (state_ == PROFILER_STARTED) {
    try {
      int error = profiler_.ExecHook(retval, index, amx_Exec);
      if (state_ == PROFILER_STOPPING
          && profiler_.call_stack()->is_empty()) {
        CompleteStop();
      }
      return error;
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return amx_Exec(amx(), retval, index);
}

ProfilerState Profiler::GetState() const {
  return state_;
}

bool Profiler::Attach() {
  try {
    if (amx_path_.empty()) {
      return false;
    }
    if (state_ >= PROFILER_ATTACHED) {
      return false;
    }

    if (amxprof::HasDebugInfo(amx())) {
      if (debug_info_.Load(amx_path_)) {
        profiler_.set_debug_info(&debug_info_);
      } else {
        Printf("Error loading debug info: %s",
                aux_StrError(debug_info_.last_error()));
      }
    }

    if (debug_info_.is_loaded()) {
      Printf("Attached profiler to %s", amx_name_.c_str());
    } else {
      Printf("Attached profiler to %s (no debug info)", amx_name_.c_str());
    }

    state_ = PROFILER_ATTACHED;
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}

bool Profiler::Start() {
  if (state_ < PROFILER_ATTACHED) {
    state_ = PROFILER_ATTACHING;
    return true;
  }
  if (state_ >= PROFILER_ATTACHED) {
    state_ = PROFILER_STARTING;
    return true;
  }
  return false;
}

void Profiler::CompleteStart() {
  Printf("Started profiling %s", amx_name_.c_str());
  state_ = PROFILER_STARTED;
}

bool Profiler::Stop() {
  if (state_ >= PROFILER_STARTED) {
    state_ = PROFILER_STOPPING;
    return true;
  }
  return false;
}

void Profiler::CompleteStop() {
  Printf("Stopped profiling %s", amx_name_.c_str());
  state_ = PROFILER_STOPPED;
}

bool Profiler::Dump() const {
  try {
    if (state_ < PROFILER_ATTACHED) {
      return false;
    }

    Printf("Dumping profiling statistics for %s", amx_name_.c_str());

    std::vector<amxprof::FunctionStatistics*> fn_stats;
    profiler_.stats()->GetStatistics(fn_stats);

    int num_native_functions = 0;
    int num_public_functions = 0;
    int num_other_functions = 0;
    long num_calls = 0;

    for (std::vector<amxprof::FunctionStatistics*>::const_iterator
         iterator = fn_stats.begin();
         iterator != fn_stats.end();
         ++iterator) {
      amxprof::Function *fn = (*iterator)->function();
      if (fn->type() == amxprof::Function::NATIVE) {
        num_native_functions++;
      } else if (fn->type() == amxprof::Function::PUBLIC) {
        num_public_functions++;
      } else {
        num_other_functions++;
      }
      num_calls += (*iterator)->num_calls();
    }

    Printf("Total functions logged: %zu (native: %d, public: %d, other: %d)",
           fn_stats.size(),
           num_native_functions,
           num_public_functions,
           num_other_functions);
    Printf("Total function calls logged: %ld", num_calls);

    std::string output_format = cfg::output_format;
    if (output_format.empty()) {
      output_format = cfg::old::profile_format;
    }
    ToLower(output_format);
    std::string profile_filename =
        amx_name_ + "-profile." + output_format;
    std::ofstream profile_stream(profile_filename.c_str());

    if (profile_stream.is_open()) {
      amxprof::StatisticsWriter *writer = 0;

      if (output_format == "html") {
        writer = new amxprof::StatisticsWriterHtml;
      } else if (output_format == "txt" || output_format == "text") {
        writer = new amxprof::StatisticsWriterText;
      } else if (output_format == "json") {
        writer = new amxprof::StatisticsWriterJson;
      } else {
        Printf("Unsupported output format '%s'", output_format.c_str());
      }

      if (writer != 0) {
        Printf("Writing profile to %s", profile_filename.c_str());
        writer->set_stream(&profile_stream);
        writer->set_script_name(amx_path_);
        writer->set_print_date(true);
        writer->set_print_run_time(true);
        writer->Write(profiler_.stats());
        delete writer;
      }

      profile_stream.close();
    } else {
      Printf("Error opening '%s' for writing", profile_filename.c_str());
    }

    if (IsCallGraphEnabled()) {
      std::string call_graph_format = cfg::call_graph_format;
      if (call_graph_format.empty()) {
        call_graph_format = cfg::old::call_graph_format;
      }
      ToLower(call_graph_format);
      std::string call_graph_filename =
          amx_name_ + "-calls." + call_graph_format;
      std::ofstream call_graph_stream(call_graph_filename.c_str());

      if (call_graph_stream.is_open()) {
        amxprof::CallGraphWriterDot *writer = 0;

        if (call_graph_format == "dot") {
          writer = new amxprof::CallGraphWriterDot;
        } else {
          Printf("Unsupported call graph format '%s'",
                  call_graph_format.c_str());
        }

        if (writer != 0) {
          Printf("Writing call graph to %s", call_graph_filename.c_str());
          writer->set_stream(&call_graph_stream);
          writer->set_script_name(amx_path_);
          writer->set_root_node_name("SA-MP Server");
          writer->Write(profiler_.call_graph());
          delete writer;
        }

        call_graph_stream.close();
      } else {
        Printf("Error opening %s for writing", call_graph_filename.c_str());
      }
    }
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}
<commit_msg>Replace %zu with %llu<commit_after>// Copyright (c) 2011-2014 Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <exception>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <amxprof/call_graph_writer_dot.h>
#include <amxprof/function.h>
#include <amxprof/function_statistics.h>
#include <amxprof/statistics_writer_html.h>
#include <amxprof/statistics_writer_json.h>
#include <amxprof/statistics_writer_text.h>
#include "amxpath.h"
#include "fileutils.h"
#include "logprintf.h"
#include "profiler.h"

#define logprintf Use_Printf_isntead_of_logprintf

namespace {
namespace cfg {

ConfigReader server_cfg("server.cfg");

std::string gamemodes =
    server_cfg.GetValueWithDefault("profiler_gamemodes");
std::vector<std::string> filterscripts =
    server_cfg.GetValues<std::string>("profiler_filterscripts");
std::string output_format =
    server_cfg.GetValueWithDefault("profiler_outputformat", "html");
bool call_graph =
    server_cfg.GetValueWithDefault("profiler_callgraph", false);
std::string call_graph_format =
    server_cfg.GetValueWithDefault("profiler_callgraphformat", "dot");

namespace old {

// old config variables.
bool profile_gamemode =
    server_cfg.GetValueWithDefault("profile_gamemode", false);
std::vector<std::string> profile_filterscripts =
    server_cfg.GetValues<std::string>("profile_filterscripts");
std::string profile_format =
    server_cfg.GetValueWithDefault("profile_format", "html");
bool call_graph =
    server_cfg.GetValueWithDefault("call_graph", false);
std::string call_graph_format =
    server_cfg.GetValueWithDefault("call_graph_format", "dot");

} // namespace old
} // namespace cfg

void Printf(const char *format, ...) {
  std::va_list va;
  va_start(va, format);

  std::string new_format;
  new_format.append("[profiler] ");
  new_format.append(format);

  vlogprintf(new_format.c_str(), va);
  va_end(va);
}

void PrintException(const std::exception &e) {
  Printf("Error: %s", e.what());
}

void SplitString(const std::string &s,
                 char delim,
                 std::vector<std::string> &comps) {
  std::string::size_type begin = 0;
  std::string::size_type end;

  while (begin < s.length()) {
    end = s.find(delim, begin);
    end = (end == std::string::npos) ? s.length() : end;
    comps.push_back(std::string(s.begin() + begin, s.begin() + end));
    begin = end + 1;
  }
}

void ToLower(std::string &s) {
  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

std::string ToUnixPath(std::string path) {
  std::replace(path.begin(), path.end(), '\\', '/');
  return path;
}

bool IsCallGraphEnabled() {
  return cfg::call_graph || cfg::old::call_graph;
}

bool IsGameMode(const std::string &amx_path) {
  return amx_path.find("gamemodes/") != std::string::npos;
}

bool IsFilterScript(const std::string &amx_path) {
  return amx_path.find("filterscripts/") != std::string::npos;
}

bool ShouldBeProfiled(const std::string amx_path) {
  if (IsGameMode(amx_path)) {
    if (cfg::old::profile_gamemode) {
      return true;
    }
    std::vector<std::string> gm_names;
    SplitString(cfg::gamemodes, ' ', gm_names);
    for (std::vector<std::string>::const_iterator iterator = gm_names.begin();
         iterator != gm_names.end(); ++iterator) {
      const std::string &gm_name = *iterator;
      if (fileutils::SameFile(amx_path, "gamemodes/" + gm_name + ".amx") ||
          fileutils::SameFile(amx_path, "gamemodes/" + gm_name)) {
        return true;
      }
    }
  }
  if (IsFilterScript(amx_path)) {
    std::vector<std::string> fs_names;
    std::copy(cfg::old::profile_filterscripts.begin(),
              cfg::old::profile_filterscripts.end(),
              std::back_inserter(fs_names));
    std::copy(cfg::filterscripts.begin(),
              cfg::filterscripts.end(),
              std::back_inserter(fs_names));
    for (std::vector<std::string>::const_iterator iterator = fs_names.begin();
         iterator != fs_names.end(); ++iterator) {
      const std::string &fs_name = *iterator;
      if (fileutils::SameFile(amx_path, "filterscripts/" + fs_name + ".amx") ||
          fileutils::SameFile(amx_path, "filterscripts/" + fs_name)) {
        return true;
      }
    }
  }
  return false;
}

} // anonymous namespace

Profiler::Profiler(AMX *amx)
 : AMXService<Profiler>(amx),
   prev_debug_(amx->debug),
   prev_callback_(amx->callback),
   profiler_(amx, IsCallGraphEnabled()),
   state_(PROFILER_DISABLED)
{
  AmxPathFinder amx_path_finder;
  amx_path_finder.AddSearchDirectory("gamemodes");
  amx_path_finder.AddSearchDirectory("filterscripts");

  const char *amx_search_path = getenv("AMX_PATH");
  if (amx_search_path != 0) {
    std::vector<std::string> dirs;
    SplitString(amx_search_path, fileutils::kNativePathListSepChar, dirs);
    for (std::vector<std::string>::const_iterator iterator = dirs.begin();
         iterator != dirs.end(); ++iterator) {
      amx_path_finder.AddSearchDirectory(*iterator);
    }
  }

  amx_path_ = ToUnixPath(amx_path_finder.FindAmxPath(amx));
  amx_name_ = fileutils::GetDirectory(amx_path_)
            + "/"
            + fileutils::GetBaseName(amx_path_);

  if (amx_path_.empty()) {
    Printf("Could not find AMX file (try setting AMX_PATH?)");
  }
}

int Profiler::Load() {
  if (ShouldBeProfiled(amx_path_)) {
    Attach();
  }
  return AMX_ERR_NONE;
}

int Profiler::Unload() {
  return AMX_ERR_NONE;
}

int Profiler::Debug() {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.DebugHook(prev_debug_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  if (prev_debug_ != 0) {
    return prev_debug_(amx());
  }
  return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.CallbackHook(index, result, params, prev_callback_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return prev_callback_(amx(), index, result, params);
}

int Profiler::Exec(cell *retval, int index) {
  if (profiler_.call_stack()->is_empty()) {
    switch (state_) {
      case PROFILER_ATTACHING:
        if (!Attach()) {
          break;
        }
        // fallthrough
      case PROFILER_STARTING:
        CompleteStart();
        break;
    }
  }
  if (state_ == PROFILER_STARTED) {
    try {
      int error = profiler_.ExecHook(retval, index, amx_Exec);
      if (state_ == PROFILER_STOPPING
          && profiler_.call_stack()->is_empty()) {
        CompleteStop();
      }
      return error;
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return amx_Exec(amx(), retval, index);
}

ProfilerState Profiler::GetState() const {
  return state_;
}

bool Profiler::Attach() {
  try {
    if (amx_path_.empty()) {
      return false;
    }
    if (state_ >= PROFILER_ATTACHED) {
      return false;
    }

    if (amxprof::HasDebugInfo(amx())) {
      if (debug_info_.Load(amx_path_)) {
        profiler_.set_debug_info(&debug_info_);
      } else {
        Printf("Error loading debug info: %s",
                aux_StrError(debug_info_.last_error()));
      }
    }

    if (debug_info_.is_loaded()) {
      Printf("Attached profiler to %s", amx_name_.c_str());
    } else {
      Printf("Attached profiler to %s (no debug info)", amx_name_.c_str());
    }

    state_ = PROFILER_ATTACHED;
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}

bool Profiler::Start() {
  if (state_ < PROFILER_ATTACHED) {
    state_ = PROFILER_ATTACHING;
    return true;
  }
  if (state_ >= PROFILER_ATTACHED) {
    state_ = PROFILER_STARTING;
    return true;
  }
  return false;
}

void Profiler::CompleteStart() {
  Printf("Started profiling %s", amx_name_.c_str());
  state_ = PROFILER_STARTED;
}

bool Profiler::Stop() {
  if (state_ >= PROFILER_STARTED) {
    state_ = PROFILER_STOPPING;
    return true;
  }
  return false;
}

void Profiler::CompleteStop() {
  Printf("Stopped profiling %s", amx_name_.c_str());
  state_ = PROFILER_STOPPED;
}

bool Profiler::Dump() const {
  try {
    if (state_ < PROFILER_ATTACHED) {
      return false;
    }

    Printf("Dumping profiling statistics for %s", amx_name_.c_str());

    std::vector<amxprof::FunctionStatistics*> fn_stats;
    profiler_.stats()->GetStatistics(fn_stats);

    int num_native_functions = 0;
    int num_public_functions = 0;
    int num_other_functions = 0;
    long num_calls = 0;

    for (std::vector<amxprof::FunctionStatistics*>::const_iterator
         iterator = fn_stats.begin();
         iterator != fn_stats.end();
         ++iterator) {
      amxprof::Function *fn = (*iterator)->function();
      if (fn->type() == amxprof::Function::NATIVE) {
        num_native_functions++;
      } else if (fn->type() == amxprof::Function::PUBLIC) {
        num_public_functions++;
      } else {
        num_other_functions++;
      }
      num_calls += (*iterator)->num_calls();
    }

    Printf("Total functions logged: %llu (native: %d, public: %d, other: %d)",
           (unsigned long long)fn_stats.size(),
           num_native_functions,
           num_public_functions,
           num_other_functions);
    Printf("Total function calls logged: %ld", num_calls);

    std::string output_format = cfg::output_format;
    if (output_format.empty()) {
      output_format = cfg::old::profile_format;
    }
    ToLower(output_format);
    std::string profile_filename =
        amx_name_ + "-profile." + output_format;
    std::ofstream profile_stream(profile_filename.c_str());

    if (profile_stream.is_open()) {
      amxprof::StatisticsWriter *writer = 0;

      if (output_format == "html") {
        writer = new amxprof::StatisticsWriterHtml;
      } else if (output_format == "txt" || output_format == "text") {
        writer = new amxprof::StatisticsWriterText;
      } else if (output_format == "json") {
        writer = new amxprof::StatisticsWriterJson;
      } else {
        Printf("Unsupported output format '%s'", output_format.c_str());
      }

      if (writer != 0) {
        Printf("Writing profile to %s", profile_filename.c_str());
        writer->set_stream(&profile_stream);
        writer->set_script_name(amx_path_);
        writer->set_print_date(true);
        writer->set_print_run_time(true);
        writer->Write(profiler_.stats());
        delete writer;
      }

      profile_stream.close();
    } else {
      Printf("Error opening '%s' for writing", profile_filename.c_str());
    }

    if (IsCallGraphEnabled()) {
      std::string call_graph_format = cfg::call_graph_format;
      if (call_graph_format.empty()) {
        call_graph_format = cfg::old::call_graph_format;
      }
      ToLower(call_graph_format);
      std::string call_graph_filename =
          amx_name_ + "-calls." + call_graph_format;
      std::ofstream call_graph_stream(call_graph_filename.c_str());

      if (call_graph_stream.is_open()) {
        amxprof::CallGraphWriterDot *writer = 0;

        if (call_graph_format == "dot") {
          writer = new amxprof::CallGraphWriterDot;
        } else {
          Printf("Unsupported call graph format '%s'",
                  call_graph_format.c_str());
        }

        if (writer != 0) {
          Printf("Writing call graph to %s", call_graph_filename.c_str());
          writer->set_stream(&call_graph_stream);
          writer->set_script_name(amx_path_);
          writer->set_root_node_name("SA-MP Server");
          writer->Write(profiler_.call_graph());
          delete writer;
        }

        call_graph_stream.close();
      } else {
        Printf("Error opening %s for writing", call_graph_filename.c_str());
      }
    }
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}
<|endoftext|>


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

#include <algorithm>
#include <cassert>
#include <map>
#include <numeric>
#include <sstream>
#include <string>

#include "abstract_printer.h"
#include "function.h"
#include "profile.h"
#include "profiler.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

namespace {

int AMXAPI Debug(AMX *amx) {
	return samp_profiler::Profiler::Get(amx)->Debug();
}

// Reads from a code section at a given location.
inline cell ReadAmxCode(AMX *amx, cell where) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	return *reinterpret_cast<cell*>(amx->base + hdr->cod + where);
}

} // anonymous namespace

namespace samp_profiler {

// statics
std::map<AMX*, Profiler*> Profiler::instances_;

Profiler::Profiler() {}

bool Profiler::IsScriptProfilable(AMX *amx) {
	uint16_t flags;
	amx_Flags(amx, &flags);

	if ((flags & AMX_FLAG_DEBUG) != 0) {
		return true;
	}

	if ((flags & AMX_FLAG_NOCHECKS) == 0) {
		return true;
	}

	return false;
}

// static
void Profiler::Attach(AMX *amx) {
	Profiler *prof = new Profiler(amx);
	instances_[amx] = prof;
	prof->Activate();
}

// static
void Profiler::Attach(AMX *amx, const DebugInfo &debug_info) {
	Attach(amx);
	Get(amx)->SetDebugInfo(debug_info);
}

// static
void Profiler::Detach(AMX *amx) {
	Profiler *prof = Profiler::Get(amx);
	if (prof != 0) {
		prof->Deactivate();
		delete prof;
	}
	instances_.erase(amx);
}

// static
Profiler *Profiler::Get(AMX *amx) {
	std::map<AMX*, Profiler*>::iterator it = instances_.find(amx);
	if (it != instances_.end()) {
		return it->second;
	}
	return 0;
}

Profiler::Profiler(AMX *amx)
	: active_(false)
	, amx_(amx)
	, debug_(amx->debug)
{
	// Since PrintStats is done in AmxUnload and amx->base is already freed before
	// AmxUnload gets called, therefore both native and public tables are not accessible,
	// from there, so they must be stored separately in some global place.
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);
	AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);
	int num_publics;
	amx_NumPublics(amx_, &num_publics);
	for (int i = 0; i < num_publics; i++) {
		public_names_.push_back(reinterpret_cast<char*>(amx->base + publics[i].nameofs));
	}
	int num_natives;
	amx_NumNatives(amx_, &num_natives);
	for (int i = 0; i < num_natives; i++) {
		native_names_.push_back(reinterpret_cast<char*>(amx->base + natives[i].nameofs));
	}
}

void Profiler::SetDebugInfo(const DebugInfo &info) {
	debug_info_ = info;
}

void Profiler::Activate() {
	if (!active_) {
		active_ = true;
		amx_SetDebugHook(amx_, ::Debug);
	}
}

bool Profiler::IsActive() const {
	return active_;
}

void Profiler::Deactivate() {
	if (active_) {
		active_ = false;
		amx_SetDebugHook(amx_, debug_);
	}
}

void Profiler::ResetStats() {
	functions_.clear();
}

void Profiler::PrintStats(std::ostream &stream, AbstractPrinter *printer) const {
	Profile profile;

	for (std::set<Function>::const_iterator iterator = functions_.begin();
			iterator != functions_.end(); ++iterator)
	{
		std::string name;
		std::string type;

		switch (iterator->type()) {
		case Function::NATIVE: {
			name = native_names_[iterator->index()];
			type = "native";
			break;
		}
		case Function::PUBLIC: {
			if (iterator->index() >= 0) {
				name = public_names_[iterator->index()];
				type = "public";
			} else if (iterator->index() == AMX_EXEC_MAIN) {
				name = "main";
				type = "main";
			}
			break;
		}
		case Function::NORMAL: {
			type = "normal";
			bool name_found = false;
			if (debug_info_.IsLoaded()) {
				name = debug_info_.GetFunction(iterator->address());
				if (!name.empty()) {
					name_found = true;
				}
			}
			if (!name_found) {
				std::stringstream ss;
				ss << "unknown@0x" << std::hex << iterator->address();
				ss >> name;
			}
			break;
		}
		default:
			assert(0 && "Invalid function type");
		}

		profile.push_back(ProfileEntry(name, type, iterator->time(), iterator->child_time(),
				iterator->num_calls()));
	}

	printer->Print(stream, profile);
}

int Profiler::Debug() {
	cell prevFrame = amx_->stp;
	if (!call_stack_.IsEmpty()) {
		prevFrame = call_stack_.GetTop().frame();
	}

	if (amx_->frm < prevFrame) {
		cell address = amx_->cip - 2*sizeof(cell);
		std::string name = debug_info_.GetFunction(address);
		if (call_stack_.GetTop().frame() != amx_->frm) {
			EnterFunction(CallInfo(Function::Normal(address), amx_->frm));
		}
	} else if (amx_->frm > prevFrame) {
		Function top_fn = call_stack_.GetTop().function();
		if (top_fn.type() == Function::NORMAL) {
			LeaveFunction(top_fn);
		}
	}

	if (debug_ != 0) {
		return debug_(amx_);
	}
	return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
	EnterFunction(CallInfo(Function::Native(index), amx_->frm));
	int error = amx_Callback(amx_, index, result, params);
	LeaveFunction(Function::Native(index));
	return error;
}

int Profiler::Exec(cell *retval, int index) {
	if (index >= 0 || index == AMX_EXEC_MAIN) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
		cell address = 0;
		if (index == AMX_EXEC_MAIN) {
			address = hdr->cip;
		} else {
			AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
			address = publics[index].address;
		}
		EnterFunction(CallInfo(Function::Public(index),
			amx_->stk - 3*sizeof(cell)));
		// Why 3?
		// - one for parameter count (amx->paramcount)
		// - another is zero return address
		// - stk is the third, pushed by PROC opcode
		int error = amx_Exec(amx_, retval, index);
		LeaveFunction(Function::Public(index));
		return error;
	} else {
		return amx_Exec(amx_, retval, index);
	}
}

void Profiler::EnterFunction(const CallInfo &call) {
	call_stack_.Push(call);
	std::set<Function>::iterator iterator = functions_.find(call.function());
	if (iterator == functions_.end()) {
		Function f = call.function();
		f.IncreaseCalls();
		functions_.insert(f);
	} else {
		iterator->IncreaseCalls();
	}
}

void Profiler::LeaveFunction(const Function &function) {
	while (true) {
		CallInfo current = call_stack_.Pop();
		std::set<Function>::iterator current_it = functions_.find(current.function());
		if (current_it != functions_.end()) {
			current_it->AdjustTime(current.timer().total_time());
		}
		if (!call_stack_.IsEmpty()) {
			// Adjust caller's child_time
			CallInfo top = call_stack_.GetTop();
			std::set<Function>::iterator top_it = functions_.find(top.function());
			if (top_it != functions_.end()) {
				top_it->AdjustChildTime(current.timer().total_time());
			}
		}
		if (current.function() == function) {
			break;
		}
	}
}

} // namespace samp_profiler
<commit_msg>Delete a forgotten line of code used to debug Profielr::Debug<commit_after>// SA:MP Profiler plugin
//
// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cassert>
#include <map>
#include <numeric>
#include <sstream>
#include <string>

#include "abstract_printer.h"
#include "function.h"
#include "profile.h"
#include "profiler.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

namespace {

int AMXAPI Debug(AMX *amx) {
	return samp_profiler::Profiler::Get(amx)->Debug();
}

// Reads from a code section at a given location.
inline cell ReadAmxCode(AMX *amx, cell where) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	return *reinterpret_cast<cell*>(amx->base + hdr->cod + where);
}

} // anonymous namespace

namespace samp_profiler {

// statics
std::map<AMX*, Profiler*> Profiler::instances_;

Profiler::Profiler() {}

bool Profiler::IsScriptProfilable(AMX *amx) {
	uint16_t flags;
	amx_Flags(amx, &flags);

	if ((flags & AMX_FLAG_DEBUG) != 0) {
		return true;
	}

	if ((flags & AMX_FLAG_NOCHECKS) == 0) {
		return true;
	}

	return false;
}

// static
void Profiler::Attach(AMX *amx) {
	Profiler *prof = new Profiler(amx);
	instances_[amx] = prof;
	prof->Activate();
}

// static
void Profiler::Attach(AMX *amx, const DebugInfo &debug_info) {
	Attach(amx);
	Get(amx)->SetDebugInfo(debug_info);
}

// static
void Profiler::Detach(AMX *amx) {
	Profiler *prof = Profiler::Get(amx);
	if (prof != 0) {
		prof->Deactivate();
		delete prof;
	}
	instances_.erase(amx);
}

// static
Profiler *Profiler::Get(AMX *amx) {
	std::map<AMX*, Profiler*>::iterator it = instances_.find(amx);
	if (it != instances_.end()) {
		return it->second;
	}
	return 0;
}

Profiler::Profiler(AMX *amx)
	: active_(false)
	, amx_(amx)
	, debug_(amx->debug)
{
	// Since PrintStats is done in AmxUnload and amx->base is already freed before
	// AmxUnload gets called, therefore both native and public tables are not accessible,
	// from there, so they must be stored separately in some global place.
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);
	AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);
	int num_publics;
	amx_NumPublics(amx_, &num_publics);
	for (int i = 0; i < num_publics; i++) {
		public_names_.push_back(reinterpret_cast<char*>(amx->base + publics[i].nameofs));
	}
	int num_natives;
	amx_NumNatives(amx_, &num_natives);
	for (int i = 0; i < num_natives; i++) {
		native_names_.push_back(reinterpret_cast<char*>(amx->base + natives[i].nameofs));
	}
}

void Profiler::SetDebugInfo(const DebugInfo &info) {
	debug_info_ = info;
}

void Profiler::Activate() {
	if (!active_) {
		active_ = true;
		amx_SetDebugHook(amx_, ::Debug);
	}
}

bool Profiler::IsActive() const {
	return active_;
}

void Profiler::Deactivate() {
	if (active_) {
		active_ = false;
		amx_SetDebugHook(amx_, debug_);
	}
}

void Profiler::ResetStats() {
	functions_.clear();
}

void Profiler::PrintStats(std::ostream &stream, AbstractPrinter *printer) const {
	Profile profile;

	for (std::set<Function>::const_iterator iterator = functions_.begin();
			iterator != functions_.end(); ++iterator)
	{
		std::string name;
		std::string type;

		switch (iterator->type()) {
		case Function::NATIVE: {
			name = native_names_[iterator->index()];
			type = "native";
			break;
		}
		case Function::PUBLIC: {
			if (iterator->index() >= 0) {
				name = public_names_[iterator->index()];
				type = "public";
			} else if (iterator->index() == AMX_EXEC_MAIN) {
				name = "main";
				type = "main";
			}
			break;
		}
		case Function::NORMAL: {
			type = "normal";
			bool name_found = false;
			if (debug_info_.IsLoaded()) {
				name = debug_info_.GetFunction(iterator->address());
				if (!name.empty()) {
					name_found = true;
				}
			}
			if (!name_found) {
				std::stringstream ss;
				ss << "unknown@0x" << std::hex << iterator->address();
				ss >> name;
			}
			break;
		}
		default:
			assert(0 && "Invalid function type");
		}

		profile.push_back(ProfileEntry(name, type, iterator->time(), iterator->child_time(),
				iterator->num_calls()));
	}

	printer->Print(stream, profile);
}

int Profiler::Debug() {
	cell prevFrame = amx_->stp;
	if (!call_stack_.IsEmpty()) {
		prevFrame = call_stack_.GetTop().frame();
	}

	if (amx_->frm < prevFrame) {
		cell address = amx_->cip - 2*sizeof(cell);
		if (call_stack_.GetTop().frame() != amx_->frm) {
			EnterFunction(CallInfo(Function::Normal(address), amx_->frm));
		}
	} else if (amx_->frm > prevFrame) {
		Function top_fn = call_stack_.GetTop().function();
		if (top_fn.type() == Function::NORMAL) {
			LeaveFunction(top_fn);
		}
	}

	if (debug_ != 0) {
		return debug_(amx_);
	}
	return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
	EnterFunction(CallInfo(Function::Native(index), amx_->frm));
	int error = amx_Callback(amx_, index, result, params);
	LeaveFunction(Function::Native(index));
	return error;
}

int Profiler::Exec(cell *retval, int index) {
	if (index >= 0 || index == AMX_EXEC_MAIN) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
		cell address = 0;
		if (index == AMX_EXEC_MAIN) {
			address = hdr->cip;
		} else {
			AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
			address = publics[index].address;
		}
		EnterFunction(CallInfo(Function::Public(index),
			amx_->stk - 3*sizeof(cell)));
		// Why 3?
		// - one for parameter count (amx->paramcount)
		// - another is zero return address
		// - stk is the third, pushed by PROC opcode
		int error = amx_Exec(amx_, retval, index);
		LeaveFunction(Function::Public(index));
		return error;
	} else {
		return amx_Exec(amx_, retval, index);
	}
}

void Profiler::EnterFunction(const CallInfo &call) {
	call_stack_.Push(call);
	std::set<Function>::iterator iterator = functions_.find(call.function());
	if (iterator == functions_.end()) {
		Function f = call.function();
		f.IncreaseCalls();
		functions_.insert(f);
	} else {
		iterator->IncreaseCalls();
	}
}

void Profiler::LeaveFunction(const Function &function) {
	while (true) {
		CallInfo current = call_stack_.Pop();
		std::set<Function>::iterator current_it = functions_.find(current.function());
		if (current_it != functions_.end()) {
			current_it->AdjustTime(current.timer().total_time());
		}
		if (!call_stack_.IsEmpty()) {
			// Adjust caller's child_time
			CallInfo top = call_stack_.GetTop();
			std::set<Function>::iterator top_it = functions_.find(top.function());
			if (top_it != functions_.end()) {
				top_it->AdjustChildTime(current.timer().total_time());
			}
		}
		if (current.function() == function) {
			break;
		}
	}
}

} // namespace samp_profiler
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.

#include <time.h>

#include <string>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "debug.hpp"
#include "arch/runtime/thread_pool.hpp"   /* for `run_in_blocker_pool()` */
#include "containers/archive/file_stream.hpp"
#include "http/file_app.hpp"
#include "logger.hpp"
#include "stl_utils.hpp"
#include "time.hpp"
#include "http/web_assets.hpp"

file_http_app_t::file_http_app_t(std::string _asset_dir)
    : asset_dir(_asset_dir)
{ }

bool ends_with(const std::string& str, const std::string& end) {
    return str.rfind(end) == str.length() - end.length();
}

void file_http_app_t::handle(const http_req_t &req, http_res_t *result, signal_t *) {
    if (req.method != GET) {
        *result = http_res_t(HTTP_METHOD_NOT_ALLOWED);
        return;
    }

    std::string resource(req.resource.as_string());

    std::string filename;

    if (resource == "/" || resource == "") {
        filename = "/index.html";
    } else {
        filename = resource;
    }

    std::pair<const char *, size_t> resource_data;
    try {
        resource_data = static_web_assets.at(filename);
    } catch (std::out_of_range) {
        printf_buffer_t resource_buffer;
        debug_print_quoted_string(&resource_buffer,
                                  reinterpret_cast<const uint8_t *>(resource.data()),
                                  resource.length());
        logNTC("Someone asked for the nonwhitelisted file %s.  If this should be "
               "accessible, add it to the static web assets.", resource_buffer.c_str());
        *result = http_res_t(HTTP_FORBIDDEN);
        return;
    }

    time_t expires;
#ifndef NDEBUG
    // In debug mode, do not cache static web assets
    expires = get_secs() - 31536000; // Some time in the past (one year ago)
#else
    // In release mode, cache static web assets except index.html
    if (filename == "/index.html") {
        expires = get_secs() - 31536000; // Some time in the past (one year ago)
    } else {
        expires = get_secs() + 31536000; // One year from now
    }
#endif
    result->add_header_line("Expires", http_format_date(expires));

    // TODO more robust mimetype detection?
    std::string mimetype = "text/plain";
    if (ends_with(filename, ".js")) {
        mimetype = "text/javascript";
    } else if (ends_with(filename, ".css")) {
        mimetype = "text/css";
    } else if (ends_with(filename, ".html")) {
        mimetype = "text/html";
    } else if (ends_with(filename, ".woff")) {
        mimetype = "application/font-woff";
    } else if (ends_with(filename, ".eot")) {
        mimetype = "application/vnd.ms-fontobject";
    } else if (ends_with(filename, ".ttf")) {
        mimetype = "application/x-font-ttf";
    } else if (ends_with(filename, ".svg")) {
        mimetype = "image/svg+xml";
    } else if (ends_with(filename, ".ico")) {
        mimetype = "image/vnd.microsoft.icon";
    } else if (ends_with(filename, ".png")) {
        mimetype = "image/png";
    } else if (ends_with(filename, ".gif")) {
        mimetype = "image/gif";
    }
    result->add_header_line("Content-Type", mimetype);

    if (asset_dir.empty()) {
        result->body.assign(resource_data.first, resource_data.second);
        result->code = 200;
    } else {
        thread_pool_t::run_in_blocker_pool(boost::bind(&file_http_app_t::handle_blocking, this, filename, result));

        if (result->code == 404) {
            logNTC("File %s was requested and is on the whitelist but we didn't find it in the directory.", (asset_dir + filename).c_str());
        }
    }
}

void file_http_app_t::handle_blocking(std::string filename, http_res_t *res_out) {

    // FIXME: make sure that we won't walk out of our sandbox! Check symbolic links, etc.
    blocking_read_file_stream_t stream;
    bool initialized = stream.init((asset_dir + filename).c_str());

    if (!initialized) {
        res_out->code = 404;
        return;
    }

    std::vector<char> body;

    for (;;) {
        const int bufsize = 4096;
        char buf[bufsize];
        int64_t res = stream.read(buf, bufsize);

        if (res > 0) {
            body.insert(body.end(), buf, buf + res);
        } else if (res == 0) {
            break;
        } else {
            res_out->code = 500;
            return;
        }
    }

    res_out->body.assign(body.begin(), body.end());
    res_out->code = 200;
}
<commit_msg>use map::find instead of map::at<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.

#include <time.h>

#include <string>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "debug.hpp"
#include "arch/runtime/thread_pool.hpp"   /* for `run_in_blocker_pool()` */
#include "containers/archive/file_stream.hpp"
#include "http/file_app.hpp"
#include "logger.hpp"
#include "stl_utils.hpp"
#include "time.hpp"
#include "http/web_assets.hpp"

file_http_app_t::file_http_app_t(std::string _asset_dir)
    : asset_dir(_asset_dir)
{ }

bool ends_with(const std::string& str, const std::string& end) {
    return str.rfind(end) == str.length() - end.length();
}

void file_http_app_t::handle(const http_req_t &req, http_res_t *result, signal_t *) {
    if (req.method != GET) {
        *result = http_res_t(HTTP_METHOD_NOT_ALLOWED);
        return;
    }

    std::string resource(req.resource.as_string());

    std::string filename;

    if (resource == "/" || resource == "") {
        filename = "/index.html";
    } else {
        filename = resource;
    }

    auto it = static_web_assets.find(filename);
    if (it == static_web_assets.end()) {
        printf_buffer_t resource_buffer;
        debug_print_quoted_string(&resource_buffer,
                                  reinterpret_cast<const uint8_t *>(resource.data()),
                                  resource.length());
        logNTC("Someone asked for the nonwhitelisted file %s.  If this should be "
               "accessible, add it to the static web assets.", resource_buffer.c_str());
        *result = http_res_t(HTTP_FORBIDDEN);
        return;
    }

    const std::pair<const char *, size_t> &resource_data = it->second;

    time_t expires;
#ifndef NDEBUG
    // In debug mode, do not cache static web assets
    expires = get_secs() - 31536000; // Some time in the past (one year ago)
#else
    // In release mode, cache static web assets except index.html
    if (filename == "/index.html") {
        expires = get_secs() - 31536000; // Some time in the past (one year ago)
    } else {
        expires = get_secs() + 31536000; // One year from now
    }
#endif
    result->add_header_line("Expires", http_format_date(expires));

    // TODO more robust mimetype detection?
    std::string mimetype = "text/plain";
    if (ends_with(filename, ".js")) {
        mimetype = "text/javascript";
    } else if (ends_with(filename, ".css")) {
        mimetype = "text/css";
    } else if (ends_with(filename, ".html")) {
        mimetype = "text/html";
    } else if (ends_with(filename, ".woff")) {
        mimetype = "application/font-woff";
    } else if (ends_with(filename, ".eot")) {
        mimetype = "application/vnd.ms-fontobject";
    } else if (ends_with(filename, ".ttf")) {
        mimetype = "application/x-font-ttf";
    } else if (ends_with(filename, ".svg")) {
        mimetype = "image/svg+xml";
    } else if (ends_with(filename, ".ico")) {
        mimetype = "image/vnd.microsoft.icon";
    } else if (ends_with(filename, ".png")) {
        mimetype = "image/png";
    } else if (ends_with(filename, ".gif")) {
        mimetype = "image/gif";
    }
    result->add_header_line("Content-Type", mimetype);

    if (asset_dir.empty()) {
        result->body.assign(resource_data.first, resource_data.second);
        result->code = 200;
    } else {
        thread_pool_t::run_in_blocker_pool(boost::bind(&file_http_app_t::handle_blocking, this, filename, result));

        if (result->code == 404) {
            logNTC("File %s was requested and is on the whitelist but we didn't find it in the directory.", (asset_dir + filename).c_str());
        }
    }
}

void file_http_app_t::handle_blocking(std::string filename, http_res_t *res_out) {

    // FIXME: make sure that we won't walk out of our sandbox! Check symbolic links, etc.
    blocking_read_file_stream_t stream;
    bool initialized = stream.init((asset_dir + filename).c_str());

    if (!initialized) {
        res_out->code = 404;
        return;
    }

    std::vector<char> body;

    for (;;) {
        const int bufsize = 4096;
        char buf[bufsize];
        int64_t res = stream.read(buf, bufsize);

        if (res > 0) {
            body.insert(body.end(), buf, buf + res);
        } else if (res == 0) {
            break;
        } else {
            res_out->code = 500;
            return;
        }
    }

    res_out->body.assign(body.begin(), body.end());
    res_out->code = 200;
}
<|endoftext|>


<commit_before>#include "eteditor.h"

void eteditor::setetype(etype* e) {
  entitytype=e;
}

void eteditor::setfont(font* fontset) {
  f=fontset;
}

void eteditor::setrenderer(SDL_Renderer* renderer) {
  r=renderer;
}

void eteditor::draw() {
  f->drawf(256,256,{255,255,255,255},0,0,"%d",(entitytype==NULL));
  if (entitytype!=NULL) {
    f->draw(w-128, offY+2, color[0], 1, 0, false, "Events");
    SDL_RenderDrawLine(r, w, offY+20, w-256, offY+20);
    SDL_RenderDrawLine(r, w-256, offY, w-256, h);
  }
}

void eteditor::setcolor(int colindex, SDL_Color colcol) {
  color[colindex]=colcol;
}

eteditor::eteditor() {
  entitytype=NULL;
}<commit_msg>event editor buttons layout<commit_after>#include "eteditor.h"

void eteditor::setetype(etype* e) {
  entitytype=e;
}

void eteditor::setfont(font* fontset) {
  f=fontset;
}

void eteditor::setrenderer(SDL_Renderer* renderer) {
  r=renderer;
}

void eteditor::draw() {
  f->drawf(256,256,{255,255,255,255},0,0,"%d",(entitytype==NULL));
  if (entitytype!=NULL) {
    f->draw(w-128, offY+2, color[0], 1, 0, false, "Events");
    SDL_RenderDrawLine(r, w, offY+20, w-256, offY+20);
    SDL_RenderDrawLine(r, w, offY+40, w-256, offY+40);
    SDL_RenderDrawLine(r, w-256, offY, w-256, h);

    SDL_RenderDrawLine(r, w-85, offY+20, w-85, offY+40);
    SDL_RenderDrawLine(r, w-171, offY+20, w-171, offY+40);

    f->draw(w-214, offY+22, color[0], 1, 0, 0, "Add");
    f->draw(w-128, offY+22, color[0], 1, 0, 0, "Change");
    f->draw(w-43, offY+22, color[0], 1, 0, 0, "Remove");
  }
}

void eteditor::setcolor(int colindex, SDL_Color colcol) {
  color[colindex]=colcol;
}

eteditor::eteditor() {
  entitytype=NULL;
}<|endoftext|>