<commit_before>#include "Crown.h"
#include "Terrain.h"
#include "FPSSystem.h"
#include "Game.h"

using namespace crown;

class WndCtrl: public KeyboardListener
{
public:

	WndCtrl()
	{
		device()->input_manager()->register_keyboard_listener(this);
	}

	void key_released(const KeyboardEvent& event)
	{
		if (event.key == KC_ESCAPE)
		{
			device()->stop();
		}
	}
};

class MainScene: public KeyboardListener, public MouseListener
{

public:

	MainScene() :
		optShowSkybox(true),
		optShowCrate(true),
		optShowTerrain(true),
		camera_active(true)
	{
		device()->input_manager()->register_keyboard_listener(this);
		device()->input_manager()->register_mouse_listener(this);
		mouseRightPressed = false;
		mouseLeftPressed = false;
	}

	~MainScene()
	{
	}

	void key_released(const KeyboardEvent& event)
	{
		if (event.key == '1')
		{
			terrain.PlotCircle(2, 2, 2, 2);
		}

		if (event.key == '2')
		{
			terrain.PlotCircle(4, 4, 4, 2);
		}

		if (event.key == '3')
		{
			terrain.PlotCircle(8, 8, 8, 2);
		}

		if (event.key == KC_F5)
		{
			device()->reload(grass);
		}

		if (event.key == KC_SPACE)
		{
			camera_active = !camera_active;
		}
	}

	void button_pressed(const MouseEvent& event)
	{
		if (event.button == MB_LEFT)
		{
			mouseLeftPressed = true;

			//GLint view[4];
			//GLdouble proj[16], model[16];

			//glGetDoublev(GL_MODELVIEW_MATRIX, model);
			//glGetDoublev(GL_PROJECTION_MATRIX, proj);
			//glGetIntegerv(GL_VIEWPORT, view);

			//int x = event.x;
			//int y = event.y;

			// Adjust y wndCoord
			//y = (625 - y);

			//double sX, sY, sZ;
			//double eX, eY, eZ;

			//gluUnProject(x, y, 0.0f, model, proj, view, &sX, &sY, &sZ);
			//gluUnProject(x, y, 1.0f, model, proj, view, &eX, &eY, &eZ);

			//Vec3 dir = Vec3(eX, eY, eZ) - Vec3(sX, sY, sZ);

			//dir.normalize();

			//ray.direction = dir;
		}
		else if (event.button == MB_RIGHT)
		{
			mouseRightPressed = true;
		}
		wheel += event.wheel * 0.25;
	}

	void button_released(const MouseEvent& event)
	{
		if (event.button == MB_LEFT)
		{
			mouseLeftPressed = false;
		}
		else if (event.button == MB_RIGHT)
		{
			mouseRightPressed = false;
		}
		wheel -= event.wheel * 0.25;
	}

	void on_load()
	{
		crown::Renderer* renderer = crown::device()->renderer();

		Vec3 start = Vec3(0.0f, 10.0f, 0.0f);

		// Add a movable camera
		cam = new Camera(start, 90.0f, 1.6f);
		system = new FPSSystem(cam, 10.0f, 2.5f);
		// Add a skybox
		skybox = new Skybox(Vec3::ZERO, true);

		terrain.CreateTerrain(64, 64, 1, 0.0f);
		terrain.PlotCircle(4, 4, 4, 2);
		terrain.UpdateVertexBuffer(true);

		red_north = device()->load("textures/red_north.tga");
		red_south = device()->load("textures/red_south.tga");
		red_east  = device()->load("textures/red_east.tga");
		red_west  = device()->load("textures/red_west.tga");
		red_up    = device()->load("textures/red_up.tga");
		red_down  = device()->load("textures/red_down.tga");
		grass     = device()->load("textures/grass.tga");

		device()->resource_manager()->flush();

		TextureResource* grass_texture = (TextureResource*)device()->data(grass);
		grass_id = device()->renderer()->load_texture(grass_texture);
	}

	void on_unload()
	{
		device()->unload(grass);
		device()->unload(red_north);
		device()->unload(red_south);
		device()->unload(red_east);
		device()->unload(red_west);
		device()->unload(red_up);
		device()->unload(red_down);
	}

	void render(float dt)
	{
		Renderer* renderer = device()->renderer();

		renderer->set_clear_color(Color4::LIGHTBLUE);

		if (camera_active)
		{
			system->set_view_by_cursor();
		}
		system->update(dt);

		renderer->set_lighting(false);
		renderer->set_texturing(0, false);

		if (skybox)
		{
			skybox->Render();
		}

		ray.set_origin(cam->position());
		ray.set_direction(cam->look_at());

		/* Render the terrain */
		renderer->set_ambient_light(Color4(0.5f, 0.5f, 0.5f, 1.0f));

		renderer->set_lighting(true);
		renderer->set_light(0, true);
		renderer->set_light_params(0, LT_DIRECTION, Vec3(0.6, 0.5f, -2.0f));
		renderer->set_light_color(0, Color4::WHITE, Color4::WHITE, Color4(0.6f, 0.6f, 0.6f));
		renderer->set_light_attenuation(0, 1, 0, 0);

		renderer->set_material_params(Color4(0.3f, 0.3f, 0.3f), Color4(0.8f, 0.8f, 0.8f), Color4::BLACK, Color4::BLACK, 0);

		renderer->set_matrix(MT_MODEL, Mat4::IDENTITY);

		if (device()->is_loaded(grass))
		{
			renderer->set_texturing(0, true);
			renderer->set_texture(0, grass_id);
		}

		//glColor3f(1, 1, 1);

		terrain.Render();

		/* Test for intersection */
		Triangle tri, tri2;
		real dist;
		if (terrain.TraceRay(ray, tri, tri2, dist))
		{
			renderer->set_depth_test(false);
			Vec3 intersectionPoint = ray.origin() + (ray.direction() * dist);
			if (mouseLeftPressed)
			{
				terrain.ApplyBrush(intersectionPoint, 0.09f);
				terrain.UpdateVertexBuffer(true);
			}
			if (mouseRightPressed)
			{
				terrain.ApplyBrush(intersectionPoint, -0.09f);
				terrain.UpdateVertexBuffer(true);
			}
			renderer->set_depth_test(true);
		}
	}

private:

	FPSSystem* system;
	Camera* cam;
	Skybox* skybox;
	Mat4 ortho;
	Terrain terrain;

	// Resources
	ResourceId grass;
	ResourceId red_north;
	ResourceId red_south;
	ResourceId red_east;
	ResourceId red_west;
	ResourceId red_up;
	ResourceId red_down;
	TextureId grass_id;

	bool optShowSkybox;
	bool optShowCrate;
	bool optShowTerrain;
	bool mouseLeftPressed;
	bool mouseRightPressed;
	float wheel;
	bool camera_active;
	Ray ray;
};

class TerrainGame : public Game
{
public:

	void init()
	{
		m_scene.on_load();
	}

	void shutdown()
	{
		m_scene.on_unload();
	}

	void update(float dt)
	{
		m_scene.render(dt);
	}

private:

	MainScene m_scene;
	WndCtrl m_ctrl;
};

extern "C" Game* create_game()
{
	return new TerrainGame;
}

extern "C" void destroy_game(Game* game)
{
	delete game;
}

<commit_msg>Update terrain sample<commit_after>#include "Crown.h"
#include "Terrain.h"
#include "FPSSystem.h"
#include "Game.h"

using namespace crown;

class WndCtrl: public KeyboardListener
{
public:

	WndCtrl()
	{
		device()->input_manager()->register_keyboard_listener(this);
	}

	void key_released(const KeyboardEvent& event)
	{
		if (event.key == KC_ESCAPE)
		{
			device()->stop();
		}
	}
};

class MainScene: public KeyboardListener, public MouseListener
{

public:

	MainScene() :
		optShowSkybox(true),
		optShowCrate(true),
		optShowTerrain(true),
		camera_active(true)
	{
		device()->input_manager()->register_keyboard_listener(this);
		device()->input_manager()->register_mouse_listener(this);
		mouseRightPressed = false;
		mouseLeftPressed = false;
	}

	~MainScene()
	{
	}

	void key_released(const KeyboardEvent& event)
	{
		if (event.key == '1')
		{
			terrain.PlotCircle(2, 2, 2, 2);
		}

		if (event.key == '2')
		{
			terrain.PlotCircle(4, 4, 4, 2);
		}

		if (event.key == '3')
		{
			terrain.PlotCircle(8, 8, 8, 2);
		}

		if (event.key == KC_F5)
		{
			device()->reload(grass);
		}

		if (event.key == KC_SPACE)
		{
			camera_active = !camera_active;
		}
	}

	void button_pressed(const MouseEvent& event)
	{
		if (event.button == MB_LEFT)
		{
			mouseLeftPressed = true;

			//GLint view[4];
			//GLdouble proj[16], model[16];

			//glGetDoublev(GL_MODELVIEW_MATRIX, model);
			//glGetDoublev(GL_PROJECTION_MATRIX, proj);
			//glGetIntegerv(GL_VIEWPORT, view);

			//int x = event.x;
			//int y = event.y;

			// Adjust y wndCoord
			//y = (625 - y);

			//double sX, sY, sZ;
			//double eX, eY, eZ;

			//gluUnProject(x, y, 0.0f, model, proj, view, &sX, &sY, &sZ);
			//gluUnProject(x, y, 1.0f, model, proj, view, &eX, &eY, &eZ);

			//Vec3 dir = Vec3(eX, eY, eZ) - Vec3(sX, sY, sZ);

			//dir.normalize();

			//ray.direction = dir;
		}
		else if (event.button == MB_RIGHT)
		{
			mouseRightPressed = true;
		}
		wheel += event.wheel * 0.25;
	}

	void button_released(const MouseEvent& event)
	{
		if (event.button == MB_LEFT)
		{
			mouseLeftPressed = false;
		}
		else if (event.button == MB_RIGHT)
		{
			mouseRightPressed = false;
		}
		wheel -= event.wheel * 0.25;
	}

	void on_load()
	{
		crown::Renderer* renderer = crown::device()->renderer();

		Vec3 start = Vec3(0.0f, 10.0f, 0.0f);

		// Add a movable camera
		cam = new Camera(start, 90.0f, 1.6f);
		system = new FPSSystem(cam, 10.0f, 2.5f);
		// Add a skybox
		skybox = new Skybox(Vec3::ZERO, true);

		terrain.CreateTerrain(64, 64, 1, 0.0f);
		terrain.PlotCircle(4, 4, 4, 2);
		terrain.UpdateVertexBuffer(true);

		red_north = device()->load("textures/red_north.tga");
		red_south = device()->load("textures/red_south.tga");
		red_east  = device()->load("textures/red_east.tga");
		red_west  = device()->load("textures/red_west.tga");
		red_up    = device()->load("textures/red_up.tga");
		red_down  = device()->load("textures/red_down.tga");
		grass     = device()->load("textures/grass.tga");

		device()->resource_manager()->flush();

		TextureResource* grass_texture = (TextureResource*)device()->data(grass);
		grass_id = device()->renderer()->load_texture(grass_texture);
	}

	void on_unload()
	{
		device()->unload(grass);
		device()->unload(red_north);
		device()->unload(red_south);
		device()->unload(red_east);
		device()->unload(red_west);
		device()->unload(red_up);
		device()->unload(red_down);
	}

	void render(float dt)
	{
		Renderer* renderer = device()->renderer();

		renderer->set_clear_color(Color4::LIGHTBLUE);

		if (camera_active)
		{
			system->set_view_by_cursor();
		}
		system->update(dt);

		renderer->set_lighting(false);
		renderer->set_texturing(0, false);

		if (skybox)
		{
			skybox->Render();
		}

		ray.set_origin(cam->position());
		ray.set_direction(cam->look_at());

		/* Render the terrain */
		renderer->set_ambient_light(Color4(0.5f, 0.5f, 0.5f, 1.0f));

		renderer->set_lighting(true);
		renderer->set_light(0, true);
		renderer->set_light_params(0, LT_DIRECTION, Vec3(0.6, 0.5f, -2.0f));
		renderer->set_light_color(0, Color4::WHITE, Color4::WHITE, Color4(0.6f, 0.6f, 0.6f));
		renderer->set_light_attenuation(0, 1, 0, 0);

		renderer->set_material_params(Color4(0.3f, 0.3f, 0.3f), Color4(0.8f, 0.8f, 0.8f), Color4::BLACK, Color4::BLACK, 0);

		renderer->set_matrix(MT_MODEL, Mat4::IDENTITY);

		if (device()->is_loaded(grass))
		{
			renderer->set_texturing(0, true);
			renderer->set_texture(0, grass_id);
		}

		//glColor3f(1, 1, 1);

		terrain.Render();

		/* Test for intersection */
		Triangle tri, tri2;
		real dist;
		if (terrain.TraceRay(ray, tri, tri2, dist))
		{
			renderer->set_depth_test(false);
			Vec3 intersectionPoint = ray.origin() + (ray.direction() * dist);
			if (mouseLeftPressed)
			{
				terrain.ApplyBrush(intersectionPoint, 0.09f);
				terrain.UpdateVertexBuffer(true);
			}
			if (mouseRightPressed)
			{
				terrain.ApplyBrush(intersectionPoint, -0.09f);
				terrain.UpdateVertexBuffer(true);
			}
			renderer->set_depth_test(true);
		}
	}

private:

	FPSSystem* system;
	Camera* cam;
	Skybox* skybox;
	Mat4 ortho;
	Terrain terrain;

	// Resources
	ResourceId grass;
	ResourceId red_north;
	ResourceId red_south;
	ResourceId red_east;
	ResourceId red_west;
	ResourceId red_up;
	ResourceId red_down;
	TextureId grass_id;

	bool optShowSkybox;
	bool optShowCrate;
	bool optShowTerrain;
	bool mouseLeftPressed;
	bool mouseRightPressed;
	float wheel;
	bool camera_active;
	Ray ray;
};

MainScene m_scene;
WndCtrl m_ctrl;

extern "C"
{
	void init()
	{
		m_scene.on_load();
	}

	void shutdown()
	{
		m_scene.on_unload();
	}

	void frame(float dt)
	{
		m_scene.render(dt);
	}
}
<|endoftext|>


<commit_before>#include <boost/python.hpp>
#include <boost/cstdint.hpp>

#include <Magick++/Blob.h>

using namespace boost::python;

namespace  {
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(Magick_Blob_updateNoCopy_overloads_2_3, updateNoCopy, 2, 3)
}

static void update_wrapper(Magick::Blob& blob, const std::string& data) {
    blob.update(data.c_str(),data.size());
}

static std::string get_blob_data(const Magick::Blob& blob) {
    const char* data = static_cast<const char*>(blob.data());
    size_t length = blob.length();
    return std::string(data,data+length);
}

void __Blob()
{
    scope* Magick_Blob_scope = new scope(
    class_< Magick::Blob >("Blob", init<  >())
        .def(init< const void*, size_t >())
        .def(init< const Magick::Blob& >())
        .def("base64", (void (Magick::Blob::*)(const std::string) )&Magick::Blob::base64)
        .def("base64", (std::string (Magick::Blob::*)() )&Magick::Blob::base64)
        .def("update", &update_wrapper)
        .def("updateNoCopy", &Magick::Blob::updateNoCopy, Magick_Blob_updateNoCopy_overloads_2_3())
        .def("length", &Magick::Blob::length)
    );

    enum_< Magick::Blob::Allocator >("Allocator")
        .value("NewAllocator", Magick::Blob::NewAllocator)
        .value("MallocAllocator", Magick::Blob::MallocAllocator)
    ;

    delete Magick_Blob_scope;

    def("get_blob_data", &get_blob_data);
}
<commit_msg>fix to avoid build error with boost-python 1.60<commit_after>#include <boost/python.hpp>
#include <boost/cstdint.hpp>

#include <Magick++/Blob.h>

using namespace boost::python;

static void updateNoCopy_wrapper(Magick::Blob& blob, std::string& data) {
    // NOTE: this is valid?
    std::string str;
    char* w = new char[data.size() + 1];
    std::copy(str.begin(), str.end(), w);
    w[str.size()] = '\0';
    blob.updateNoCopy(w,data.size(),Magick::Blob::NewAllocator);
}

static void update_wrapper(Magick::Blob& blob, const std::string& data) {
    blob.update(data.c_str(),data.size());
}

static std::string get_blob_data(const Magick::Blob& blob) {
    const char* data = static_cast<const char*>(blob.data());
    size_t length = blob.length();
    return std::string(data,data+length);
}

void __Blob()
{
    scope* Magick_Blob_scope = new scope(
    class_< Magick::Blob >("Blob", init<  >())
        .def("__init__", &update_wrapper)       // NOTE: valid?
        .def(init< const Magick::Blob& >())
        .def("base64", (void (Magick::Blob::*)(const std::string) )&Magick::Blob::base64)
        .def("base64", (std::string (Magick::Blob::*)() )&Magick::Blob::base64)
        .def("update", &update_wrapper)
        .def("updateNoCopy", &updateNoCopy_wrapper)
        .def("length", &Magick::Blob::length)
    );

    enum_< Magick::Blob::Allocator >("Allocator")
        .value("NewAllocator", Magick::Blob::NewAllocator)
        .value("MallocAllocator", Magick::Blob::MallocAllocator)
    ;

    delete Magick_Blob_scope;

    def("get_blob_data", &get_blob_data);
}
<|endoftext|>


<commit_before>#include "WebProfile.h"

#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QTimer>
#include <QDesktopServices>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

#include "Hearthstone.h"

#include "Settings.h"

#define DEFAULT_WEBSERVICE_URL "https://trackobot.com"

WebProfile::WebProfile( QObject *parent )
  : QObject( parent )
{
  connect( &mNetworkManager, &QNetworkAccessManager::sslErrors, this, &WebProfile::SSLErrors );
}

bool JsonFromReply( QNetworkReply *reply, QJsonObject *object ) {
  QByteArray jsonData = reply->readAll();
  QJsonParseError error;
  *object = QJsonDocument::fromJson( jsonData, &error ).object();

  if( error.error != QJsonParseError::NoError ) {
    ERR( "Couldn't parse response %s", qt2cstr( error.errorString() ) );
    return false;
  }

  DBG( "Received %s", qt2cstr( QString( jsonData ) ) );
  return true;
}

void WebProfile::EnsureAccountIsSetUp() {
  if( !Settings::Instance()->HasAccount() ) {
    LOG( "No account setup. Creating one for you." );
    CreateAndStoreAccount();
  } else {
    LOG( "Account %s found", qt2cstr( Settings::Instance()->AccountUsername() ) );
  }
}

void WebProfile::UploadResult( const QJsonObject& result )
{
  QJsonObject params;
  params[ "result" ] = result;

  // Optional upload metadata to find out room for improvements
  if( Settings::Instance()->DebugEnabled() ) {
    METADATA( "GAME_WIDTH", Hearthstone::Instance()->Width() );
    METADATA( "GAME_HEIGHT", Hearthstone::Instance()->Height() );
    METADATA( "TOB_VERSION", VERSION );
    METADATA( "PLATFORM", PLATFORM );

    QJsonObject meta;
    for( auto it : Metadata::Instance()->Map().toStdMap() ) {
      const QString& key = it.first;
      const QString& value = it.second;

      meta[ key ] = value;
    }

    params[ "_meta" ] = meta;
  }
  Metadata::Instance()->Clear();

  QByteArray data = QJsonDocument( params ).toJson();

  QNetworkReply *reply = AuthPostJson( "/profile/results.json", data );
  connect( reply, &QNetworkReply::finished, [&, reply, result]() {
    int replyCode = reply->error();

    if( replyCode == QNetworkReply::NoError ) {
      QJsonObject response;
      if( JsonFromReply( reply, &response) ) {
        emit UploadResultSucceeded( response );
      }
    } else {
      int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
      emit UploadResultFailed( result, replyCode, statusCode );
    }

    reply->deleteLater();
  });
}

QNetworkReply* WebProfile::AuthPostJson( const QString& path, const QByteArray& data ) {
  QString credentials = "Basic " +
    ( Settings::Instance()->AccountUsername() +
      ":" +
      Settings::Instance()->AccountPassword()
    ).toLatin1().toBase64();

  QNetworkRequest request = CreateWebProfileRequest( path );
  request.setRawHeader( "Authorization", credentials.toLatin1() );
  request.setHeader( QNetworkRequest::ContentTypeHeader, "application/json" );
  return mNetworkManager.post( request, data );
}

QNetworkRequest WebProfile::CreateWebProfileRequest( const QString& path ) {
  QUrl url( WebserviceURL( path ) );
  QNetworkRequest request( url );
  request.setRawHeader( "User-Agent", "Track-o-Bot/" VERSION PLATFORM );
  return request;
}

void WebProfile::CreateAndStoreAccount() {
  QNetworkRequest request = CreateWebProfileRequest( "/users.json" );
  QNetworkReply *reply = mNetworkManager.post( request, "" );
  connect( reply, &QNetworkReply::finished, this, &WebProfile::CreateAndStoreAccountHandleReply );
}

void WebProfile::CreateAndStoreAccountHandleReply() {
  QNetworkReply *reply = static_cast< QNetworkReply* >( sender() );
  if( reply->error() == QNetworkReply::NoError ) {
    LOG( "Account creation was successful!" );

    QJsonObject user;
    if( JsonFromReply( reply, &user ) ) {
      LOG( "Welcome %s", qt2cstr( user[ "username" ].toString() ) );

      Settings::Instance()->SetAccount(
          user["username"].toString(),
          user["password"].toString() );
    }
  } else {
    int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
    ERR( "There was a problem creating an account. Error: %i HTTP Status Code: %i", reply->error(), statusCode );
  }

  reply->deleteLater();
}

void WebProfile::OpenProfile() {
  QNetworkReply *reply = AuthPostJson( "/one_time_auth.json", "" );
  connect( reply, &QNetworkReply::finished, this, &WebProfile::OpenProfileHandleReply );
}

void WebProfile::OpenProfileHandleReply() {
  QNetworkReply *reply = static_cast< QNetworkReply* >( sender() );
  if( reply->error() == QNetworkReply::NoError ) {
    QJsonObject response;
    if( JsonFromReply( reply, &response ) ) {
      QString url = response[ "url" ].toString();
      QDesktopServices::openUrl( QUrl( url ) );
    }
  } else {
    int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
    ERR( "There was a problem creating an auth token. Error: %i HTTP Status Code: %i", reply->error(), statusCode );
  }

  reply->deleteLater();
}

QString WebProfile::WebserviceURL( const QString& path ) {
  if( Settings::Instance()->WebserviceURL().isEmpty() ) {
    Settings::Instance()->SetWebserviceURL( DEFAULT_WEBSERVICE_URL );
  }

  return Settings::Instance()->WebserviceURL() + path;
}

// Allow self-signed certificates because Qt might report
// "There root certificate of the certificate chain is self-signed, and untrusted"
// The root cert might not be trusted yet (only after we browse to the website)
// So allow allow self-signed certificates, just in case
void WebProfile::SSLErrors(QNetworkReply *reply, const QList<QSslError>& errors) {
  QList<QSslError> errorsToIgnore;

  for( const QSslError& err : errors ) {
    if( err.error() == QSslError::SelfSignedCertificate ||
        err.error() == QSslError::SelfSignedCertificateInChain )
    {
      errorsToIgnore << err;
    } else {
      ERR( "SSL Error %d", err.error() );
    }
  }

  reply->ignoreSslErrors( errorsToIgnore );
}

<commit_msg>Mac: Throw error when Qt is built with bearer management. Fixes #111<commit_after>#include "WebProfile.h"

#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QTimer>
#include <QDesktopServices>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

#include "Hearthstone.h"

#include "Settings.h"

#define DEFAULT_WEBSERVICE_URL "https://trackobot.com"

#if defined(Q_OS_MAC) && !defined(QT_NO_BEARERMANAGEMENT)
  #error Qt must be built without bearer management (-no-feature-bearermanagement) on Mac (until https://bugreports.qt.io/browse/QTBUG-50181 is fixed)
#endif

WebProfile::WebProfile( QObject *parent )
  : QObject( parent )
{
  connect( &mNetworkManager, &QNetworkAccessManager::sslErrors, this, &WebProfile::SSLErrors );
}

bool JsonFromReply( QNetworkReply *reply, QJsonObject *object ) {
  QByteArray jsonData = reply->readAll();
  QJsonParseError error;
  *object = QJsonDocument::fromJson( jsonData, &error ).object();

  if( error.error != QJsonParseError::NoError ) {
    ERR( "Couldn't parse response %s", qt2cstr( error.errorString() ) );
    return false;
  }

  DBG( "Received %s", qt2cstr( QString( jsonData ) ) );
  return true;
}

void WebProfile::EnsureAccountIsSetUp() {
  if( !Settings::Instance()->HasAccount() ) {
    LOG( "No account setup. Creating one for you." );
    CreateAndStoreAccount();
  } else {
    LOG( "Account %s found", qt2cstr( Settings::Instance()->AccountUsername() ) );
  }
}

void WebProfile::UploadResult( const QJsonObject& result )
{
  QJsonObject params;
  params[ "result" ] = result;

  // Optional upload metadata to find out room for improvements
  if( Settings::Instance()->DebugEnabled() ) {
    METADATA( "GAME_WIDTH", Hearthstone::Instance()->Width() );
    METADATA( "GAME_HEIGHT", Hearthstone::Instance()->Height() );
    METADATA( "TOB_VERSION", VERSION );
    METADATA( "PLATFORM", PLATFORM );

    QJsonObject meta;
    for( auto it : Metadata::Instance()->Map().toStdMap() ) {
      const QString& key = it.first;
      const QString& value = it.second;

      meta[ key ] = value;
    }

    params[ "_meta" ] = meta;
  }
  Metadata::Instance()->Clear();

  QByteArray data = QJsonDocument( params ).toJson();

  QNetworkReply *reply = AuthPostJson( "/profile/results.json", data );
  connect( reply, &QNetworkReply::finished, [&, reply, result]() {
    int replyCode = reply->error();

    if( replyCode == QNetworkReply::NoError ) {
      QJsonObject response;
      if( JsonFromReply( reply, &response) ) {
        emit UploadResultSucceeded( response );
      }
    } else {
      int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
      emit UploadResultFailed( result, replyCode, statusCode );
    }

    reply->deleteLater();
  });
}

QNetworkReply* WebProfile::AuthPostJson( const QString& path, const QByteArray& data ) {
  QString credentials = "Basic " +
    ( Settings::Instance()->AccountUsername() +
      ":" +
      Settings::Instance()->AccountPassword()
    ).toLatin1().toBase64();

  QNetworkRequest request = CreateWebProfileRequest( path );
  request.setRawHeader( "Authorization", credentials.toLatin1() );
  request.setHeader( QNetworkRequest::ContentTypeHeader, "application/json" );
  return mNetworkManager.post( request, data );
}

QNetworkRequest WebProfile::CreateWebProfileRequest( const QString& path ) {
  QUrl url( WebserviceURL( path ) );
  QNetworkRequest request( url );
  request.setRawHeader( "User-Agent", "Track-o-Bot/" VERSION PLATFORM );
  return request;
}

void WebProfile::CreateAndStoreAccount() {
  QNetworkRequest request = CreateWebProfileRequest( "/users.json" );
  QNetworkReply *reply = mNetworkManager.post( request, "" );
  connect( reply, &QNetworkReply::finished, this, &WebProfile::CreateAndStoreAccountHandleReply );
}

void WebProfile::CreateAndStoreAccountHandleReply() {
  QNetworkReply *reply = static_cast< QNetworkReply* >( sender() );
  if( reply->error() == QNetworkReply::NoError ) {
    LOG( "Account creation was successful!" );

    QJsonObject user;
    if( JsonFromReply( reply, &user ) ) {
      LOG( "Welcome %s", qt2cstr( user[ "username" ].toString() ) );

      Settings::Instance()->SetAccount(
          user["username"].toString(),
          user["password"].toString() );
    }
  } else {
    int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
    ERR( "There was a problem creating an account. Error: %i HTTP Status Code: %i", reply->error(), statusCode );
  }

  reply->deleteLater();
}

void WebProfile::OpenProfile() {
  QNetworkReply *reply = AuthPostJson( "/one_time_auth.json", "" );
  connect( reply, &QNetworkReply::finished, this, &WebProfile::OpenProfileHandleReply );
}

void WebProfile::OpenProfileHandleReply() {
  QNetworkReply *reply = static_cast< QNetworkReply* >( sender() );
  if( reply->error() == QNetworkReply::NoError ) {
    QJsonObject response;
    if( JsonFromReply( reply, &response ) ) {
      QString url = response[ "url" ].toString();
      QDesktopServices::openUrl( QUrl( url ) );
    }
  } else {
    int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
    ERR( "There was a problem creating an auth token. Error: %i HTTP Status Code: %i", reply->error(), statusCode );
  }

  reply->deleteLater();
}

QString WebProfile::WebserviceURL( const QString& path ) {
  if( Settings::Instance()->WebserviceURL().isEmpty() ) {
    Settings::Instance()->SetWebserviceURL( DEFAULT_WEBSERVICE_URL );
  }

  return Settings::Instance()->WebserviceURL() + path;
}

// Allow self-signed certificates because Qt might report
// "There root certificate of the certificate chain is self-signed, and untrusted"
// The root cert might not be trusted yet (only after we browse to the website)
// So allow allow self-signed certificates, just in case
void WebProfile::SSLErrors(QNetworkReply *reply, const QList<QSslError>& errors) {
  QList<QSslError> errorsToIgnore;

  for( const QSslError& err : errors ) {
    if( err.error() == QSslError::SelfSignedCertificate ||
        err.error() == QSslError::SelfSignedCertificateInChain )
    {
      errorsToIgnore << err;
    } else {
      ERR( "SSL Error %d", err.error() );
    }
  }

  reply->ignoreSslErrors( errorsToIgnore );
}

<|endoftext|>


<commit_before>/*
 * BackwardChainer.cc
 *
 * Copyright (C) 2014-2017 OpenCog Foundation
 *
 * Authors: Misgana Bayetta <misgana.bayetta@gmail.com>  October 2014
 *          William Ma <https://github.com/williampma>
 *          Nil Geisweiller 2016-2017
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <random>

#include <boost/range/algorithm/lower_bound.hpp>

#include <opencog/util/random.h>

#include <opencog/atomutils/FindUtils.h>
#include <opencog/atomutils/Substitutor.h>
#include <opencog/atomutils/Unify.h>
#include <opencog/atomutils/TypeUtils.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/atoms/pattern/BindLink.h>

#include <opencog/query/BindLinkAPI.h>

#include "BackwardChainer.h"
#include "BackwardChainerPMCB.h"
#include "UnifyPMCB.h"
#include "BCLogger.h"

using namespace opencog;

BackwardChainer::BackwardChainer(AtomSpace& as, const Handle& rbs,
                                 const Handle& target,
                                 const Handle& vardecl,
                                 const Handle& focus_set, // TODO:
                                                          // support
                                                          // focus_set
                                 const BITNodeFitness& fitness)
	: _fcs_maximum_size(2000),
	  _as(as), _configReader(as, rbs),
	  _bit(as, target, vardecl, fitness),
	  _iteration(0), _last_expansion_andbit(nullptr),
	  _rules(_configReader.get_rules()) {
}

UREConfigReader& BackwardChainer::get_config()
{
	return _configReader;
}

const UREConfigReader& BackwardChainer::get_config() const
{
	return _configReader;
}

void BackwardChainer::do_chain()
{
	while (not termination())
	{
		do_step();
	}
}

void BackwardChainer::do_step()
{
	bc_logger().debug("Iteration %d", _iteration);
	_iteration++;

	expand_bit();
	fulfill_bit();
	reduce_bit();
}

bool BackwardChainer::termination()
{
	return _configReader.get_maximum_iterations() <= _iteration;
}

Handle BackwardChainer::get_results() const
{
	HandleSeq results(_results.begin(), _results.end());
	return _as.add_link(SET_LINK, results);
}

void BackwardChainer::expand_bit()
{
	// This is kinda of hack before meta rules are fully supported by
	// the Rule class.
	size_t rules_size = _rules.size();
	_rules.expand_meta_rules(_as);

	// If the rule set has changed we need to reset the exhausted
	// flags.
	if (rules_size != _rules.size()) {
		_bit.reset_exhausted_flags();
		bc_logger().debug() << "The rule set has gone from "
		                    << rules_size << " rules to " << _rules.size()
		                    << ". All exhausted flags have been reset.";
	}

	// Reset _last_expansion_fcs
	_last_expansion_andbit = nullptr;

	if (_bit.empty()) {
		_last_expansion_andbit = _bit.init();
	} else {
		// Select an FCS (i.e. and-BIT) and expand it
		AndBIT* andbit = select_expansion_andbit();
		LAZY_BC_LOG_DEBUG << "Selected and-BIT for expansion:" << std::endl
		                  << andbit->to_string();
		expand_bit(*andbit);
	}
}

void BackwardChainer::expand_bit(AndBIT& andbit)
{
	// Select leaf
	BITNode* bitleaf = andbit.select_leaf();
	if (bitleaf) {
		LAZY_BC_LOG_DEBUG << "Selected BIT-node for expansion:" << std::endl
		                  << bitleaf->to_string();
	} else {
		bc_logger().debug() << "All BIT-nodes of this and-BIT are exhausted "
		                    << "(or possibly fulfilled). Abort expansion.";
		andbit.exhausted = true;
		return;
	}

	// Get the leaf vardecl from fcs. We don't want to filter it
	// because otherwise the typed substitution obtained may miss some
	// variables in the FCS declaration that needs to be substituted
	// during expension.
	Handle vardecl = BindLinkCast(andbit.fcs)->get_vardecl();

	// Select a valid rule
	RuleTypedSubstitutionPair rule_ts = select_rule(*bitleaf, vardecl);
	Rule rule(rule_ts.first);
	Unify::TypedSubstitution ts(rule_ts.second);
	// Add the rule in the _bit.bit_as to make comparing atoms easier
	// as well as logging more consistent.
	rule.add(_bit.bit_as);
	if (not rule.is_valid()) {
		bc_logger().debug("No valid rule for the selected BIT-node, abort expansion");
		return;
	}
	LAZY_BC_LOG_DEBUG << "Selected rule for BIT expansion:" << std::endl
	                  << rule.to_string();

	_last_expansion_andbit = _bit.expand(andbit, *bitleaf, {rule, ts});
}

void BackwardChainer::fulfill_bit()
{
	if (_bit.empty()) {
		bc_logger().warn("Cannot fulfill an empty BIT!");
		return;
	}

	// Select an and-BIT for fulfillment
	const AndBIT* andbit = select_fulfillment_andbit();
	if (andbit == nullptr) {
		bc_logger().debug() << "Cannot fulfill an empty and-BIT. "
		                    << "Abort BIT fulfillment";
		return;
	}
	LAZY_BC_LOG_DEBUG << "Selected and-BIT for fulfillment:"
	                  << andbit->fcs->idToString();
	fulfill_fcs(andbit->fcs);
}

void BackwardChainer::fulfill_fcs(const Handle& fcs)
{
	// Temporary atomspace to not pollute _as with intermediary
	// results
	AtomSpace tmp_as(&_as);

	// Run the FCS and add the results in _as
	Handle hresult = bindlink(&tmp_as, fcs);
	HandleSeq results;
	for (const Handle& result : hresult->getOutgoingSet())
		results.push_back(_as.add_atom(result));
	LAZY_BC_LOG_DEBUG << "Results:" << std::endl << results;
	_results.insert(results.begin(), results.end());
}

AndBIT* BackwardChainer::select_expansion_andbit()
{
	// Calculate distribution based on a (poor) estimate of the
	// probablity of a and-BIT being within the path of the solution.
	std::vector<double> weights;
	for (const AndBIT& andbit : _bit.andbits)
		weights.push_back(operator()(andbit));

	// Debug log
	if (bc_logger().is_debug_enabled()) {
		OC_ASSERT(weights.size() == _bit.andbits.size());
		std::stringstream ss;
		ss << "Weighted and-BITs:";
		for (size_t i = 0; i < weights.size(); i++)
			ss << std::endl << weights[i] << " "
			   << _bit.andbits[i].fcs->idToString();
		bc_logger().debug() << ss.str();
	}

	// Sample andbits according to this distribution
	std::discrete_distribution<size_t> dist(weights.begin(), weights.end());
	return &rand_element(_bit.andbits, dist);
}

const AndBIT* BackwardChainer::select_fulfillment_andbit() const
{
	return _last_expansion_andbit;
}

void BackwardChainer::reduce_bit()
{
	// TODO: reset exhausted flags related to the removed and-BITs.

	// TODO: remove least likely and-BITs

	// // Remove and-BITs above a certain size.
	// auto complex_lt = [&](const AndBIT& andbit, size_t max_size) {
	// 	return andbit.fcs->size() < max_size; };
	// auto it = boost::lower_bound(_bit.andbits, _fcs_maximum_size, complex_lt);
	// size_t previous_size = _bit.andbits.size();
	// _bit.erase(it, _bit.andbits.end());
	// if (size_t removed_andbits = previous_size - _bit.andbits.size()) {
	// 	LAZY_BC_LOG_DEBUG << "Removed " << removed_andbits
	// 	                  << " overly complex and-BITs from the BIT";
	// }
}

RuleTypedSubstitutionPair BackwardChainer::select_rule(BITNode& target,
                                                       const Handle& vardecl)
{
	// The rule is randomly selected amongst the valid ones, with
	// probability of selection being proportional to its weight.
	const RuleTypedSubstitutionMap valid_rules = get_valid_rules(target, vardecl);
	if (valid_rules.empty()) {
		target.exhausted = true;
		return {Rule(), Unify::TypedSubstitution()};;
	}

	// Log all valid rules and their weights
	if (bc_logger().is_debug_enabled()) {
		std::stringstream ss;
		ss << "The following weighted rules are valid:";
		for (const auto& r : valid_rules)
			ss << std::endl << r.first.get_weight() << " " << r.first.get_name();
		LAZY_BC_LOG_DEBUG << ss.str();
	}

	return select_rule(valid_rules);
}

RuleTypedSubstitutionPair BackwardChainer::select_rule(const RuleTypedSubstitutionMap& rules)
{
	// Build weight vector to do weighted random selection
	std::vector<double> weights;
	for (const auto& rule : rules)
		weights.push_back(rule.first.get_weight());

	// No rule exhaustion, sample one according to the distribution
	std::discrete_distribution<size_t> dist(weights.begin(), weights.end());
	return rand_element(rules, dist);
}

RuleTypedSubstitutionMap BackwardChainer::get_valid_rules(const BITNode& target,
                                                          const Handle& vardecl)
{
	// Generate all valid rules
	RuleTypedSubstitutionMap valid_rules;
	for (const Rule& rule : _rules) {
		// For now ignore meta rules as they are forwardly applied in
		// expand_bit()
		if (rule.is_meta())
			continue;

		RuleTypedSubstitutionMap unified_rules
			= rule.unify_target(target.body, vardecl);

		// Insert only rules with positive probability of success
		RuleTypedSubstitutionMap pos_rules;
		for (const auto& rule : unified_rules) {
			double p = (_bit.is_in(rule, target) ? 0.0 : 1.0)
				* rule.first.get_weight();
			if (p > 0) pos_rules.insert(rule);
		}

		valid_rules.insert(pos_rules.begin(), pos_rules.end());
	}
	return valid_rules;
}

double BackwardChainer::complexity_factor(const AndBIT& andbit) const
{
	return exp(-_configReader.get_complexity_penalty() * andbit.complexity);
}

double BackwardChainer::operator()(const AndBIT& andbit) const
{
	return (andbit.exhausted ? 0.0 : 1.0) * complexity_factor(andbit);
}
<commit_msg>Improve and-BIT fulfillment log<commit_after>/*
 * BackwardChainer.cc
 *
 * Copyright (C) 2014-2017 OpenCog Foundation
 *
 * Authors: Misgana Bayetta <misgana.bayetta@gmail.com>  October 2014
 *          William Ma <https://github.com/williampma>
 *          Nil Geisweiller 2016-2017
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <random>

#include <boost/range/algorithm/lower_bound.hpp>

#include <opencog/util/random.h>

#include <opencog/atomutils/FindUtils.h>
#include <opencog/atomutils/Substitutor.h>
#include <opencog/atomutils/Unify.h>
#include <opencog/atomutils/TypeUtils.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/atoms/pattern/BindLink.h>

#include <opencog/query/BindLinkAPI.h>

#include "BackwardChainer.h"
#include "BackwardChainerPMCB.h"
#include "UnifyPMCB.h"
#include "BCLogger.h"

using namespace opencog;

BackwardChainer::BackwardChainer(AtomSpace& as, const Handle& rbs,
                                 const Handle& target,
                                 const Handle& vardecl,
                                 const Handle& focus_set, // TODO:
                                                          // support
                                                          // focus_set
                                 const BITNodeFitness& fitness)
	: _fcs_maximum_size(2000),
	  _as(as), _configReader(as, rbs),
	  _bit(as, target, vardecl, fitness),
	  _iteration(0), _last_expansion_andbit(nullptr),
	  _rules(_configReader.get_rules()) {
}

UREConfigReader& BackwardChainer::get_config()
{
	return _configReader;
}

const UREConfigReader& BackwardChainer::get_config() const
{
	return _configReader;
}

void BackwardChainer::do_chain()
{
	while (not termination())
	{
		do_step();
	}
}

void BackwardChainer::do_step()
{
	bc_logger().debug("Iteration %d", _iteration);
	_iteration++;

	expand_bit();
	fulfill_bit();
	reduce_bit();
}

bool BackwardChainer::termination()
{
	return _configReader.get_maximum_iterations() <= _iteration;
}

Handle BackwardChainer::get_results() const
{
	HandleSeq results(_results.begin(), _results.end());
	return _as.add_link(SET_LINK, results);
}

void BackwardChainer::expand_bit()
{
	// This is kinda of hack before meta rules are fully supported by
	// the Rule class.
	size_t rules_size = _rules.size();
	_rules.expand_meta_rules(_as);

	// If the rule set has changed we need to reset the exhausted
	// flags.
	if (rules_size != _rules.size()) {
		_bit.reset_exhausted_flags();
		bc_logger().debug() << "The rule set has gone from "
		                    << rules_size << " rules to " << _rules.size()
		                    << ". All exhausted flags have been reset.";
	}

	// Reset _last_expansion_fcs
	_last_expansion_andbit = nullptr;

	if (_bit.empty()) {
		_last_expansion_andbit = _bit.init();
	} else {
		// Select an FCS (i.e. and-BIT) and expand it
		AndBIT* andbit = select_expansion_andbit();
		LAZY_BC_LOG_DEBUG << "Selected and-BIT for expansion:" << std::endl
		                  << andbit->to_string();
		expand_bit(*andbit);
	}
}

void BackwardChainer::expand_bit(AndBIT& andbit)
{
	// Select leaf
	BITNode* bitleaf = andbit.select_leaf();
	if (bitleaf) {
		LAZY_BC_LOG_DEBUG << "Selected BIT-node for expansion:" << std::endl
		                  << bitleaf->to_string();
	} else {
		bc_logger().debug() << "All BIT-nodes of this and-BIT are exhausted "
		                    << "(or possibly fulfilled). Abort expansion.";
		andbit.exhausted = true;
		return;
	}

	// Get the leaf vardecl from fcs. We don't want to filter it
	// because otherwise the typed substitution obtained may miss some
	// variables in the FCS declaration that needs to be substituted
	// during expension.
	Handle vardecl = BindLinkCast(andbit.fcs)->get_vardecl();

	// Select a valid rule
	RuleTypedSubstitutionPair rule_ts = select_rule(*bitleaf, vardecl);
	Rule rule(rule_ts.first);
	Unify::TypedSubstitution ts(rule_ts.second);
	// Add the rule in the _bit.bit_as to make comparing atoms easier
	// as well as logging more consistent.
	rule.add(_bit.bit_as);
	if (not rule.is_valid()) {
		bc_logger().debug("No valid rule for the selected BIT-node, abort expansion");
		return;
	}
	LAZY_BC_LOG_DEBUG << "Selected rule for BIT expansion:" << std::endl
	                  << rule.to_string();

	_last_expansion_andbit = _bit.expand(andbit, *bitleaf, {rule, ts});
}

void BackwardChainer::fulfill_bit()
{
	if (_bit.empty()) {
		bc_logger().warn("Cannot fulfill an empty BIT!");
		return;
	}

	// Select an and-BIT for fulfillment
	const AndBIT* andbit = select_fulfillment_andbit();
	if (andbit == nullptr) {
		bc_logger().debug() << "Cannot fulfill an empty and-BIT. "
		                    << "Abort BIT fulfillment";
		return;
	}
	LAZY_BC_LOG_DEBUG << "Selected and-BIT for fulfillment (fcs value):"
	                  << std::endl << andbit->fcs->idToString();
	fulfill_fcs(andbit->fcs);
}

void BackwardChainer::fulfill_fcs(const Handle& fcs)
{
	// Temporary atomspace to not pollute _as with intermediary
	// results
	AtomSpace tmp_as(&_as);

	// Run the FCS and add the results in _as
	Handle hresult = bindlink(&tmp_as, fcs);
	HandleSeq results;
	for (const Handle& result : hresult->getOutgoingSet())
		results.push_back(_as.add_atom(result));
	LAZY_BC_LOG_DEBUG << "Results:" << std::endl << results;
	_results.insert(results.begin(), results.end());
}

AndBIT* BackwardChainer::select_expansion_andbit()
{
	// Calculate distribution based on a (poor) estimate of the
	// probablity of a and-BIT being within the path of the solution.
	std::vector<double> weights;
	for (const AndBIT& andbit : _bit.andbits)
		weights.push_back(operator()(andbit));

	// Debug log
	if (bc_logger().is_debug_enabled()) {
		OC_ASSERT(weights.size() == _bit.andbits.size());
		std::stringstream ss;
		ss << "Weighted and-BITs:";
		for (size_t i = 0; i < weights.size(); i++)
			ss << std::endl << weights[i] << " "
			   << _bit.andbits[i].fcs->idToString();
		bc_logger().debug() << ss.str();
	}

	// Sample andbits according to this distribution
	std::discrete_distribution<size_t> dist(weights.begin(), weights.end());
	return &rand_element(_bit.andbits, dist);
}

const AndBIT* BackwardChainer::select_fulfillment_andbit() const
{
	return _last_expansion_andbit;
}

void BackwardChainer::reduce_bit()
{
	// TODO: reset exhausted flags related to the removed and-BITs.

	// TODO: remove least likely and-BITs

	// // Remove and-BITs above a certain size.
	// auto complex_lt = [&](const AndBIT& andbit, size_t max_size) {
	// 	return andbit.fcs->size() < max_size; };
	// auto it = boost::lower_bound(_bit.andbits, _fcs_maximum_size, complex_lt);
	// size_t previous_size = _bit.andbits.size();
	// _bit.erase(it, _bit.andbits.end());
	// if (size_t removed_andbits = previous_size - _bit.andbits.size()) {
	// 	LAZY_BC_LOG_DEBUG << "Removed " << removed_andbits
	// 	                  << " overly complex and-BITs from the BIT";
	// }
}

RuleTypedSubstitutionPair BackwardChainer::select_rule(BITNode& target,
                                                       const Handle& vardecl)
{
	// The rule is randomly selected amongst the valid ones, with
	// probability of selection being proportional to its weight.
	const RuleTypedSubstitutionMap valid_rules = get_valid_rules(target, vardecl);
	if (valid_rules.empty()) {
		target.exhausted = true;
		return {Rule(), Unify::TypedSubstitution()};;
	}

	// Log all valid rules and their weights
	if (bc_logger().is_debug_enabled()) {
		std::stringstream ss;
		ss << "The following weighted rules are valid:";
		for (const auto& r : valid_rules)
			ss << std::endl << r.first.get_weight() << " " << r.first.get_name();
		LAZY_BC_LOG_DEBUG << ss.str();
	}

	return select_rule(valid_rules);
}

RuleTypedSubstitutionPair BackwardChainer::select_rule(const RuleTypedSubstitutionMap& rules)
{
	// Build weight vector to do weighted random selection
	std::vector<double> weights;
	for (const auto& rule : rules)
		weights.push_back(rule.first.get_weight());

	// No rule exhaustion, sample one according to the distribution
	std::discrete_distribution<size_t> dist(weights.begin(), weights.end());
	return rand_element(rules, dist);
}

RuleTypedSubstitutionMap BackwardChainer::get_valid_rules(const BITNode& target,
                                                          const Handle& vardecl)
{
	// Generate all valid rules
	RuleTypedSubstitutionMap valid_rules;
	for (const Rule& rule : _rules) {
		// For now ignore meta rules as they are forwardly applied in
		// expand_bit()
		if (rule.is_meta())
			continue;

		RuleTypedSubstitutionMap unified_rules
			= rule.unify_target(target.body, vardecl);

		// Insert only rules with positive probability of success
		RuleTypedSubstitutionMap pos_rules;
		for (const auto& rule : unified_rules) {
			double p = (_bit.is_in(rule, target) ? 0.0 : 1.0)
				* rule.first.get_weight();
			if (p > 0) pos_rules.insert(rule);
		}

		valid_rules.insert(pos_rules.begin(), pos_rules.end());
	}
	return valid_rules;
}

double BackwardChainer::complexity_factor(const AndBIT& andbit) const
{
	return exp(-_configReader.get_complexity_penalty() * andbit.complexity);
}

double BackwardChainer::operator()(const AndBIT& andbit) const
{
	return (andbit.exhausted ? 0.0 : 1.0) * complexity_factor(andbit);
}
<|endoftext|>


<commit_before>#include "XmlElement.hpp"

#ifdef APP_DEBUG
#include <algorithm>
#endif

namespace Xml
{
    Element::Element(std::string const & name, Node * parent):
        Node(parent),
        mParent(parent),
        mchildren(),
        mComments(),
        mPI()
    {

    }

    Element::~Element()
    {

    }

    NodeList const &
    Element::elements() const
    {
        return mChildren;
    }

    Element const *
    Element::parentElement() const
    {
        Node * parent = mParent;
        do
        {
            if(parent->isElement()) break;
        }
        while((parent = mParent->parent()) != nullptr);

        return parent;
    }

    std::string
    Element::text() const
    {
        std::string content = "";

        for(auto const & c : mChildren)
        {
            content += contentText();
        }

        return content;
    }

    void
    Element::setContent(std::string const & content)
    {
        this->clearContent();
        this->appendText(content);
    }

    void
    Element::clearContent()
    {
        for(auto & c : mChildren)
        {
            if(c->isElement())
            {
                c->clearContent();
            }

            delete c;
        }
    }

    void
    Element::append(Node * node)
    {
        #ifdef APP_DEBUG
        assert(node != this);

        assert(
            std::find(std::begin(mChildren), std::end(mChildren), node)
            != std::end(mChildren)
        );
        #endif

        mChildren.append(node);
    }

    void
    Element::appendText(std::string const & text)
    {
        this->appendNode(new Text(content));
    }

    void
    Element::appendComment(std::string const & comment)
    {
        this->appendNode(new Comment(content));
    }

    void
    Element::appendPI(std::string const & pi)
    {
        this->appendNode(new PI(content));
    }

    std::string const &
    Element::name() const
    {
        return mName;
    }

    void
    Element::setName(std::string const & name)
    {
        mName = name;
    }

    std::string const &
    Element::attribute(std::string const & name) const
    {
        static std::string const notFound = "";

        auto it = mAttributes.find(name);

        return it != std::end(mAttributes) ? *it : notFound;
    }

    void
    Element::setAttribute(std::string const & name, std::string const & value)
    {
        m_attributes[name] = value;
    }

    //TODO
    void
    Element::exportToStream(std::ostream & stream, std::string const & indent) const
    {
        for(auto const & c : mChildren)
        {
            stream << indent << c->contentText();
        }
    }

    bool
    Element::isElement() const
    {
        return true;
    }
}
<commit_msg>Added resource freeing in XmlElement<commit_after>#include "XmlElement.hpp"

#ifdef APP_DEBUG
#include <algorithm>
#endif

namespace Xml
{
    Element::Element(std::string const & name, Node * parent):
        Node(parent),
        mParent(parent),
        mchildren(),
        mComments(),
        mPI()
    {

    }

    Element::~Element()
    {
        // Free memory
        this->clearContent();
    }

    NodeList const &
    Element::elements() const
    {
        return mChildren;
    }

    Element const *
    Element::parentElement() const
    {
        Node * parent = mParent;
        do
        {
            if(parent->isElement()) break;
        }
        while((parent = mParent->parent()) != nullptr);

        return parent;
    }

    std::string
    Element::text() const
    {
        std::string content = "";

        for(auto const & c : mChildren)
        {
            content += contentText();
        }

        return content;
    }

    void
    Element::setContent(std::string const & content)
    {
        this->clearContent();
        this->appendText(content);
    }

    void
    Element::clearContent()
    {
        for(auto & c : mChildren)
        {
            if(c->isElement())
            {
                c->clearContent();
            }

            delete c;
        }
    }

    void
    Element::append(Node * node)
    {
        #ifdef APP_DEBUG
        assert(node != this);

        assert(
            std::find(std::begin(mChildren), std::end(mChildren), node)
            != std::end(mChildren)
        );
        #endif

        mChildren.append(node);
    }

    void
    Element::appendText(std::string const & text)
    {
        this->appendNode(new Text(content));
    }

    void
    Element::appendComment(std::string const & comment)
    {
        this->appendNode(new Comment(content));
    }

    void
    Element::appendPI(std::string const & pi)
    {
        this->appendNode(new PI(content));
    }

    std::string const &
    Element::name() const
    {
        return mName;
    }

    void
    Element::setName(std::string const & name)
    {
        mName = name;
    }

    std::string const &
    Element::attribute(std::string const & name) const
    {
        static std::string const notFound = "";

        auto it = mAttributes.find(name);

        return it != std::end(mAttributes) ? *it : notFound;
    }

    void
    Element::setAttribute(std::string const & name, std::string const & value)
    {
        m_attributes[name] = value;
    }

    //TODO
    void
    Element::exportToStream(std::ostream & stream, std::string const & indent) const
    {
        for(auto const & c : mChildren)
        {
            stream << indent << c->contentText();
        }
    }

    bool
    Element::isElement() const
    {
        return true;
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdint.h>

#include <QtConcurrent>
#include <QException>
#include <QFileDialog>
#include <QFuture>
#include <QGraphicsRectItem>

#include "viewer.h"
#include "ui_viewer.h"

Viewer::Viewer(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Viewer),
    enabled(false),
    highlight(NULL),
    fingerprint(NULL)
{
    ui->setupUi(this);
    connect(&scanner_watcher, SIGNAL(finished()), this, SLOT(scannerFinished()));
    on_timeoutSlider_valueChanged(ui->timeoutSlider->value());

    ScannersList &scanners_list = ScannersList::getScannersList();
    for (std::vector<const char *>::iterator name = scanners_list.begin();
         name != scanners_list.end(); name++) {
        ui->scannersList->addItem(QString(*name));
    }
}

Viewer::~Viewer()
{
    delete ui;
    delete fingerprint;
}

void Viewer::highlightMinutia(int view, int minutia)
{
    if (highlight) {
            scene.removeItem(highlight);
            highlight = NULL;
    }
    if (view == 0 && minutia >= 0) {
        std::list<FingerprintMinutia>::iterator m = fingerprint->minutiaeRecord->minutiae.begin();
        std::advance(m, minutia);
        highlight = scene.addRect(m->x - 12, m->y - 12, 23, 23, QPen(QColor(0, 0xff, 0, 0xb0), 4), QBrush());
    }
}

void Viewer::scrollToMinutia(int view, int minutia)
{
    ui->templateText->scrollToAnchor(QString("view%1minutia%2").arg(view).arg(minutia));
}

void Viewer::message(QString message)
{
    ui->statusLabel->setText(message);
    ui->statusLabel->setStyleSheet("color: black; font-weight: normal;");
}

void Viewer::error(const char *message, int error)
{
    if (error)
        ui->statusLabel->setText(QString("%1 (%2)").arg(message).arg(error));
    else
        ui->statusLabel->setText(QString(message));
    ui->statusLabel->setStyleSheet("color: red; font-weight: bold;");
}

class ViewerScannerException : public QException
{
    const char *message;
    int error;

public:
    void raise() const { throw *this; }
    ViewerScannerException *clone() const { return new ViewerScannerException(*this); }

    int code() { return error; }
    const char* what() { return message; }

    ViewerScannerException(const char *message, int error = 0) : message(message), error(error) {}
};

Fingerprint *Viewer::scanStart(int timeout)
{
    Fingerprint *fingerprint = NULL;
    try {
        fingerprint = scanner->getFingerprint(timeout);
    } catch (ScannerException &e) {
        throw ViewerScannerException(e.what(), e.code());
    }

    return fingerprint;
}

class MinutiaGraphicsItem : public QGraphicsItem
{
private:
    Viewer *viewer;
    int view, minutia;
    int x, y, angle;

public:
    MinutiaGraphicsItem(Viewer *viewer, int view, int minutia, int x, int y, int angle) :
        viewer(viewer), view(view), minutia(minutia), x(x), y(y), angle(angle) {}
    QRectF boundingRect() const
    {
        return QRectF(x - 10, y - 10, 20, 20);
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {
         QPen pen(QColor(0xff, 0, 0, 0xb0), 2);
         painter->setPen(pen);

         painter->drawEllipse(x - 3, y - 3, 6, 6);

         QLineF line;
         line.setP1(QPointF(x, y));
         line.setAngle(1.0 * angle / 100000);
         line.setLength(10);
         painter->drawLine(line);
    }

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        viewer->highlightMinutia(view, minutia);
        viewer->scrollToMinutia(view, minutia);
        QGraphicsItem::mousePressEvent(event);
    }
};

void Viewer::scannerFinished()
{
    try {
        fingerprint = scanner_watcher.result();
    } catch (ViewerScannerException &e) {
        error(e.what(), e.code());
    }

    if (fingerprint && fingerprint->image) {
        QImage *image = fingerprint->image->getImage();
        pixmap = QPixmap::fromImage(*image);
        scene.addPixmap(pixmap);
        scene.setSceneRect(pixmap.rect());
        scene.addRect(pixmap.rect(), QPen(Qt::blue), QBrush());
        message(QString("Obtained %1x%2 pixels large image").arg(image->width()).arg(image->height()));
        delete image;

        ui->saveImageButton->setEnabled(true);
    }

    if (fingerprint && fingerprint->minutiaeRecord) {
        ui->templateText->setHtml(fingerprint->minutiaeRecord->getHtml());

        if (fingerprint->image) {
            for (std::list<FingerprintMinutia>::iterator m = fingerprint->minutiaeRecord->minutiae.begin();
                 m != fingerprint->minutiaeRecord->minutiae.end(); m++) {
                int index = std::distance(fingerprint->minutiaeRecord->minutiae.begin(), m);
                MinutiaGraphicsItem *minutae = new MinutiaGraphicsItem(this, 0, index, m->x, m->y, m->angle);
                minutae->setToolTip(QString("Minutia %1").arg(index));
                scene.addItem(minutae);
            }
        }

        ui->saveFMRButton->setEnabled(true);
    }

    ui->imageView->setScene(&scene);

    ui->scanButton->setEnabled(true);
    ui->onOffButton->setEnabled(true);
    ui->timeoutSlider->setEnabled(true);
}

void Viewer::on_scanButton_clicked()
{
    int timeout = ui->timeoutSlider->value();

    if (timeout == ui->timeoutSlider->maximum())
        timeout = -1;
    else
        timeout *= 1000;

    scene.clear();
    ui->templateText->clear();
    ui->saveImageButton->setEnabled(false);
    ui->saveFMRButton->setEnabled(false);

    ui->onOffButton->setEnabled(false);
    ui->timeoutSlider->setEnabled(false);
    ui->scanButton->setEnabled(false);

    delete fingerprint;
    fingerprint = NULL;

    QFuture<Fingerprint *> future = QtConcurrent::run(this, &Viewer::scanStart, timeout);
    scanner_watcher.setFuture(future);
    message("Scanning...");
}

void Viewer::on_onOffButton_clicked()
{
    if (!enabled) {
        try {
            ScannersList &scanners_list = ScannersList::getScannersList();
            scanner = new Scanner(scanners_list[ui->scannersList->currentIndex()]);
            message(QString("Turned on scanner '%1'").arg(scanner->getName()));
            enabled = true;
        } catch (ScannerException &e) {
            error(e.what(), e.code());
        }
    } else {
        message(QString("Turned off scanner '%1'").arg(scanner->getName()));
        delete scanner;
        ui->templateText->clear();
        scene.clear();
        ui->saveImageButton->setEnabled(false);
        ui->saveFMRButton->setEnabled(false);
        enabled = false;
    }

    ui->scannersList->setEnabled(!enabled);
    ui->scanButton->setEnabled(enabled);
    ui->timeoutSlider->setEnabled(enabled);
    ui->onOffButton->setText(enabled ? "Turn off" : "Turn on");
}

void Viewer::on_timeoutSlider_valueChanged(int value)
{
    QString timeout;

    if (value == ui->timeoutSlider->maximum())
        timeout = QString("infinite");
    else if (value == 0)
        timeout = QString("none");
    else if (value == 1)
        timeout = QString("1 second");
    else
        timeout = QString("%1 seconds").arg(value);

    ui->timeoutLabel->setText(QString("Timeout: %1").arg(timeout));
}

void Viewer::on_saveFMRButton_clicked()
{
    QString filter;
    QString name = QFileDialog::getSaveFileName(this, tr("Save FMR as..."), "", tr("Fingerprint Minutiae Records (*.fmr);;All Files (*)"), &filter);
    if (!name.isEmpty()) {
        if (filter.contains("fmr") && !name.endsWith(".fmr", Qt::CaseInsensitive))
            name += ".fmr";
        QFile file(name);
        file.open(QIODevice::WriteOnly);
        file.write((const char *)fingerprint->minutiaeRecord->getBinary(), fingerprint->minutiaeRecord->getSize());
        file.close();
        message(QString("%1 saved").arg(name));
    }
}

void Viewer::on_saveImageButton_clicked()
{
    QString filter;
    QString name = QFileDialog::getSaveFileName(this, tr("Save FMR as..."), "", tr("PNG Images (*.png);;JPEG Images (*.jpg);;BMP Images (*.bmp);;All Files (*)"), &filter);
    if (!name.isEmpty()) {
        if (filter.contains("png") && !name.endsWith(".png", Qt::CaseInsensitive))
            name += ".png";
        else if (filter.contains("jpg") && !name.endsWith(".jpg", Qt::CaseInsensitive) && !name.endsWith(".jpeg", Qt::CaseInsensitive))
            name += ".jpg";
        else if (filter.contains("bmp") && !name.endsWith(".bmp", Qt::CaseInsensitive))
            name += ".bmp";
        QFile file(name);
        file.open(QIODevice::WriteOnly);
        pixmap.save(&file);
        file.close();
        message(QString("%1 saved").arg(name));
    }
}
<commit_msg>viewer: Fix missing save dialog label<commit_after>#include <iostream>
#include <stdint.h>

#include <QtConcurrent>
#include <QException>
#include <QFileDialog>
#include <QFuture>
#include <QGraphicsRectItem>

#include "viewer.h"
#include "ui_viewer.h"

Viewer::Viewer(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Viewer),
    enabled(false),
    highlight(NULL),
    fingerprint(NULL)
{
    ui->setupUi(this);
    connect(&scanner_watcher, SIGNAL(finished()), this, SLOT(scannerFinished()));
    on_timeoutSlider_valueChanged(ui->timeoutSlider->value());

    ScannersList &scanners_list = ScannersList::getScannersList();
    for (std::vector<const char *>::iterator name = scanners_list.begin();
         name != scanners_list.end(); name++) {
        ui->scannersList->addItem(QString(*name));
    }
}

Viewer::~Viewer()
{
    delete ui;
    delete fingerprint;
}

void Viewer::highlightMinutia(int view, int minutia)
{
    if (highlight) {
            scene.removeItem(highlight);
            highlight = NULL;
    }
    if (view == 0 && minutia >= 0) {
        std::list<FingerprintMinutia>::iterator m = fingerprint->minutiaeRecord->minutiae.begin();
        std::advance(m, minutia);
        highlight = scene.addRect(m->x - 12, m->y - 12, 23, 23, QPen(QColor(0, 0xff, 0, 0xb0), 4), QBrush());
    }
}

void Viewer::scrollToMinutia(int view, int minutia)
{
    ui->templateText->scrollToAnchor(QString("view%1minutia%2").arg(view).arg(minutia));
}

void Viewer::message(QString message)
{
    ui->statusLabel->setText(message);
    ui->statusLabel->setStyleSheet("color: black; font-weight: normal;");
}

void Viewer::error(const char *message, int error)
{
    if (error)
        ui->statusLabel->setText(QString("%1 (%2)").arg(message).arg(error));
    else
        ui->statusLabel->setText(QString(message));
    ui->statusLabel->setStyleSheet("color: red; font-weight: bold;");
}

class ViewerScannerException : public QException
{
    const char *message;
    int error;

public:
    void raise() const { throw *this; }
    ViewerScannerException *clone() const { return new ViewerScannerException(*this); }

    int code() { return error; }
    const char* what() { return message; }

    ViewerScannerException(const char *message, int error = 0) : message(message), error(error) {}
};

Fingerprint *Viewer::scanStart(int timeout)
{
    Fingerprint *fingerprint = NULL;
    try {
        fingerprint = scanner->getFingerprint(timeout);
    } catch (ScannerException &e) {
        throw ViewerScannerException(e.what(), e.code());
    }

    return fingerprint;
}

class MinutiaGraphicsItem : public QGraphicsItem
{
private:
    Viewer *viewer;
    int view, minutia;
    int x, y, angle;

public:
    MinutiaGraphicsItem(Viewer *viewer, int view, int minutia, int x, int y, int angle) :
        viewer(viewer), view(view), minutia(minutia), x(x), y(y), angle(angle) {}
    QRectF boundingRect() const
    {
        return QRectF(x - 10, y - 10, 20, 20);
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {
         QPen pen(QColor(0xff, 0, 0, 0xb0), 2);
         painter->setPen(pen);

         painter->drawEllipse(x - 3, y - 3, 6, 6);

         QLineF line;
         line.setP1(QPointF(x, y));
         line.setAngle(1.0 * angle / 100000);
         line.setLength(10);
         painter->drawLine(line);
    }

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        viewer->highlightMinutia(view, minutia);
        viewer->scrollToMinutia(view, minutia);
        QGraphicsItem::mousePressEvent(event);
    }
};

void Viewer::scannerFinished()
{
    try {
        fingerprint = scanner_watcher.result();
    } catch (ViewerScannerException &e) {
        error(e.what(), e.code());
    }

    if (fingerprint && fingerprint->image) {
        QImage *image = fingerprint->image->getImage();
        pixmap = QPixmap::fromImage(*image);
        scene.addPixmap(pixmap);
        scene.setSceneRect(pixmap.rect());
        scene.addRect(pixmap.rect(), QPen(Qt::blue), QBrush());
        message(QString("Obtained %1x%2 pixels large image").arg(image->width()).arg(image->height()));
        delete image;

        ui->saveImageButton->setEnabled(true);
    }

    if (fingerprint && fingerprint->minutiaeRecord) {
        ui->templateText->setHtml(fingerprint->minutiaeRecord->getHtml());

        if (fingerprint->image) {
            for (std::list<FingerprintMinutia>::iterator m = fingerprint->minutiaeRecord->minutiae.begin();
                 m != fingerprint->minutiaeRecord->minutiae.end(); m++) {
                int index = std::distance(fingerprint->minutiaeRecord->minutiae.begin(), m);
                MinutiaGraphicsItem *minutae = new MinutiaGraphicsItem(this, 0, index, m->x, m->y, m->angle);
                minutae->setToolTip(QString("Minutia %1").arg(index));
                scene.addItem(minutae);
            }
        }

        ui->saveFMRButton->setEnabled(true);
    }

    ui->imageView->setScene(&scene);

    ui->scanButton->setEnabled(true);
    ui->onOffButton->setEnabled(true);
    ui->timeoutSlider->setEnabled(true);
}

void Viewer::on_scanButton_clicked()
{
    int timeout = ui->timeoutSlider->value();

    if (timeout == ui->timeoutSlider->maximum())
        timeout = -1;
    else
        timeout *= 1000;

    scene.clear();
    ui->templateText->clear();
    ui->saveImageButton->setEnabled(false);
    ui->saveFMRButton->setEnabled(false);

    ui->onOffButton->setEnabled(false);
    ui->timeoutSlider->setEnabled(false);
    ui->scanButton->setEnabled(false);

    delete fingerprint;
    fingerprint = NULL;

    QFuture<Fingerprint *> future = QtConcurrent::run(this, &Viewer::scanStart, timeout);
    scanner_watcher.setFuture(future);
    message("Scanning...");
}

void Viewer::on_onOffButton_clicked()
{
    if (!enabled) {
        try {
            ScannersList &scanners_list = ScannersList::getScannersList();
            scanner = new Scanner(scanners_list[ui->scannersList->currentIndex()]);
            message(QString("Turned on scanner '%1'").arg(scanner->getName()));
            enabled = true;
        } catch (ScannerException &e) {
            error(e.what(), e.code());
        }
    } else {
        message(QString("Turned off scanner '%1'").arg(scanner->getName()));
        delete scanner;
        ui->templateText->clear();
        scene.clear();
        ui->saveImageButton->setEnabled(false);
        ui->saveFMRButton->setEnabled(false);
        enabled = false;
    }

    ui->scannersList->setEnabled(!enabled);
    ui->scanButton->setEnabled(enabled);
    ui->timeoutSlider->setEnabled(enabled);
    ui->onOffButton->setText(enabled ? "Turn off" : "Turn on");
}

void Viewer::on_timeoutSlider_valueChanged(int value)
{
    QString timeout;

    if (value == ui->timeoutSlider->maximum())
        timeout = QString("infinite");
    else if (value == 0)
        timeout = QString("none");
    else if (value == 1)
        timeout = QString("1 second");
    else
        timeout = QString("%1 seconds").arg(value);

    ui->timeoutLabel->setText(QString("Timeout: %1").arg(timeout));
}

void Viewer::on_saveFMRButton_clicked()
{
    QString filter;
    QString name = QFileDialog::getSaveFileName(this, tr("Save FMR as..."), "", tr("Fingerprint Minutiae Records (*.fmr);;All Files (*)"), &filter);
    if (!name.isEmpty()) {
        if (filter.contains("fmr") && !name.endsWith(".fmr", Qt::CaseInsensitive))
            name += ".fmr";
        QFile file(name);
        file.open(QIODevice::WriteOnly);
        file.write((const char *)fingerprint->minutiaeRecord->getBinary(), fingerprint->minutiaeRecord->getSize());
        file.close();
        message(QString("%1 saved").arg(name));
    }
}

void Viewer::on_saveImageButton_clicked()
{
    QString filter;
    QString name = QFileDialog::getSaveFileName(this, tr("Save Image as..."), "", tr("PNG Images (*.png);;JPEG Images (*.jpg);;BMP Images (*.bmp);;All Files (*)"), &filter);
    if (!name.isEmpty()) {
        if (filter.contains("png") && !name.endsWith(".png", Qt::CaseInsensitive))
            name += ".png";
        else if (filter.contains("jpg") && !name.endsWith(".jpg", Qt::CaseInsensitive) && !name.endsWith(".jpeg", Qt::CaseInsensitive))
            name += ".jpg";
        else if (filter.contains("bmp") && !name.endsWith(".bmp", Qt::CaseInsensitive))
            name += ".bmp";
        QFile file(name);
        file.open(QIODevice::WriteOnly);
        pixmap.save(&file);
        file.close();
        message(QString("%1 saved").arg(name));
    }
}
<|endoftext|>


<commit_before><commit_msg>Pass Chrome's UA with chromeframe appended at the end in the user agent passed in ChromeFrame requests initiated in IE.<commit_after><|endoftext|>


<commit_before>// RUN: cat %s | %cling 2>&1 | FileCheck %s
// Test Interpreter::lookupFunctionProto()
#include "cling/Interpreter/Interpreter.h"
#include "clang/AST/Decl.h"

#include <cstdio>
using namespace std;

//
//  We need to fetch the global scope declaration,
//  otherwise known as the translation unit decl.
//
const clang::Decl* G = gCling->lookupScope("");
printf("G: 0x%lx\n", (unsigned long) G);
//CHECK: G: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a global function taking no args.
//

.rawInput 1
void f() { int x = 1; }
.rawInput 0

const clang::FunctionDecl* F = gCling->lookupFunctionProto(G, "f", "");
printf("F: 0x%lx\n", (unsigned long) F);
//CHECK-NEXT: F: 0x{{[1-9a-f][0-9a-f]*$}}
F->print(llvm::outs());
//CHECK-NEXT: void f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a global function taking a single int argument.
//

.rawInput 1
void a(int v) { int x = v; }
.rawInput 0

const clang::FunctionDecl* A = gCling->lookupFunctionProto(G, "a", "int");
printf("A: 0x%lx\n", (unsigned long) A);
//CHECK: A: 0x{{[1-9a-f][0-9a-f]*$}}
A->print(llvm::outs());
//CHECK-NEXT: void a(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a global function taking an int and a double argument.
//

.rawInput 1
void b(int vi, double vd) { int x = vi; double y = vd; }
.rawInput 0

const clang::FunctionDecl* B = gCling->lookupFunctionProto(G, "b", "int,double");
printf("B: 0x%lx\n", (unsigned long) B);
//CHECK: B: 0x{{[1-9a-f][0-9a-f]*$}}
B->print(llvm::outs());
//CHECK-NEXT: void b(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding a global overloaded function.
//

.rawInput 1
void c(int vi, int vj) { int x = vi; int y = vj; }
void c(int vi, double vd) { int x = vi; double y = vd; }
.rawInput 0

const clang::FunctionDecl* C1 = gCling->lookupFunctionProto(G, "c", "int,int");
printf("C1: 0x%lx\n", (unsigned long) C1);
//CHECK: C1: 0x{{[1-9a-f][0-9a-f]*$}}
C1->print(llvm::outs());
//CHECK-NEXT: void c(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* C2 = gCling->lookupFunctionProto(G, "c", "int,double");
printf("C2: 0x%lx\n", (unsigned long) C2);
//CHECK: C2: 0x{{[1-9a-f][0-9a-f]*$}}
C2->print(llvm::outs());
//CHECK-NEXT: void c(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding simple global template instantiations.
//

.rawInput 1
template <class T> void d(T v) { T x = v; }
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not.
template void d(int);
template void d(double);
.rawInput 0

const clang::FunctionDecl* D1 = gCling->lookupFunctionProto(G, "d<int>", "int");
printf("D1: 0x%lx\n", (unsigned long) D1);
//CHECK: D1: 0x{{[1-9a-f][0-9a-f]*$}}
D1->print(llvm::outs());
//CHECK-NEXT: void d(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

const clang::FunctionDecl* D2 = gCling->lookupFunctionProto(G, "d<double>", "double");
printf("D2: 0x%lx\n", (unsigned long) D2);
//CHECK: D2: 0x{{[1-9a-f][0-9a-f]*$}}
D2->print(llvm::outs());
//CHECK-NEXT: void d(double v) {
//CHECK-NEXT:     double x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking no args.
//

.rawInput 1
class A {
   void A_f() { int x = 1; }
};
.rawInput 0

const clang::Decl* class_A = gCling->lookupScope("A");
printf("class_A: 0x%lx\n", (unsigned long) class_A);
//CHECK: class_A: 0x{{[1-9a-f][0-9a-f]*$}}
const clang::FunctionDecl* class_A_F = gCling->lookupFunctionProto(class_A, "A_f", "");
printf("class_A_F: 0x%lx\n", (unsigned long) class_A_F);
//CHECK-NEXT: class_A_F: 0x{{[1-9a-f][0-9a-f]*$}}
class_A_F->print(llvm::outs());
//CHECK-NEXT: void A_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg.
//

.rawInput 1
class B {
   void B_f(int v) { int x = v; }
};
.rawInput 0

const clang::Decl* class_B = gCling->lookupScope("B");
printf("class_B: 0x%lx\n", (unsigned long) class_B);
//CHECK: class_B: 0x{{[1-9a-f][0-9a-f]*$}}
const clang::FunctionDecl* class_B_F = gCling->lookupFunctionProto(class_B, "B_f", "int");
printf("class_B_F: 0x%lx\n", (unsigned long) class_B_F);
//CHECK-NEXT: class_B_F: 0x{{[1-9a-f][0-9a-f]*$}}
class_B_F->print(llvm::outs());
//CHECK-NEXT: void B_f(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking no args in a base class.
//

.rawInput 1
class C {
   void C_f() { int x = 1; }
};
class D : public C {
};
.rawInput 0

const clang::Decl* class_D = gCling->lookupScope("D");
printf("class_D: 0x%lx\n", (unsigned long) class_D);
//CHECK: class_D: 0x{{[1-9a-f][0-9a-f]*$}}
const clang::FunctionDecl* class_D_F = gCling->lookupFunctionProto(class_D, "C_f", "");
printf("class_D_F: 0x%lx\n", (unsigned long) class_D_F);
//CHECK-NEXT: class_D_F: 0x{{[1-9a-f][0-9a-f]*$}}
class_D_F->print(llvm::outs());
//CHECK-NEXT: void C_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg in a base class.
//

.rawInput 1
class E {
   void E_f(int v) { int x = v; }
};
class F : public E {
};
.rawInput 0

const clang::Decl* class_F = gCling->lookupScope("F");
printf("class_F: 0x%lx\n", (unsigned long) class_F);
//CHECK: class_F: 0x{{[1-9a-f][0-9a-f]*$}}
const clang::FunctionDecl* class_F_F = gCling->lookupFunctionProto(class_F, "E_f", "int");
printf("class_F_F: 0x%lx\n", (unsigned long) class_F_F);
//CHECK-NEXT: class_F_F: 0x{{[1-9a-f][0-9a-f]*$}}
class_F_F->print(llvm::outs());
//CHECK-NEXT: void E_f(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  One final check to make sure we are at the right line in the output.
//

"abc"
//CHECK: (const char [4]) @0x{{[0-9a-f]+}}
<commit_msg>Use same tests and test classes as funcargs.C.<commit_after>// RUN: cat %s | %cling 2>&1 | FileCheck %s
// Test Interpreter::lookupFunctionProto()
#include "cling/Interpreter/Interpreter.h"
#include "clang/AST/Decl.h"

#include <cstdio>
using namespace std;

//
//  We need to fetch the global scope declaration,
//  otherwise known as the translation unit decl.
//
const clang::Decl* G = gCling->lookupScope("");
printf("G: 0x%lx\n", (unsigned long) G);
//CHECK: G: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a global function taking no args.
//

.rawInput 1
void f() { int x = 1; }
void a(int v) { int x = v; }
void b(int vi, double vd) { int x = vi; double y = vd; }
void c(int vi, int vj) { int x = vi; int y = vj; }
void c(int vi, double vd) { int x = vi; double y = vd; }
template <class T> void d(T v) { T x = v; }
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not, so we explicitly request the instantiations we are
//       going to lookup so they will be there to find.
template void d(int);
template void d(double);
.rawInput 0

const clang::FunctionDecl* F = gCling->lookupFunctionProto(G, "f", "");
printf("F: 0x%lx\n", (unsigned long) F);
//CHECK-NEXT: F: 0x{{[1-9a-f][0-9a-f]*$}}
F->print(llvm::outs());
//CHECK-NEXT: void f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a global function taking a single int argument.
//

const clang::FunctionDecl* A = gCling->lookupFunctionProto(G, "a", "int");
printf("A: 0x%lx\n", (unsigned long) A);
//CHECK: A: 0x{{[1-9a-f][0-9a-f]*$}}
A->print(llvm::outs());
//CHECK-NEXT: void a(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a global function taking an int and a double argument.
//

const clang::FunctionDecl* B = gCling->lookupFunctionProto(G, "b", "int,double");
printf("B: 0x%lx\n", (unsigned long) B);
//CHECK: B: 0x{{[1-9a-f][0-9a-f]*$}}
B->print(llvm::outs());
//CHECK-NEXT: void b(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding a global overloaded function.
//

const clang::FunctionDecl* C1 = gCling->lookupFunctionProto(G, "c", "int,int");
printf("C1: 0x%lx\n", (unsigned long) C1);
//CHECK: C1: 0x{{[1-9a-f][0-9a-f]*$}}
C1->print(llvm::outs());
//CHECK-NEXT: void c(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* C2 = gCling->lookupFunctionProto(G, "c", "int,double");
printf("C2: 0x%lx\n", (unsigned long) C2);
//CHECK: C2: 0x{{[1-9a-f][0-9a-f]*$}}
C2->print(llvm::outs());
//CHECK-NEXT: void c(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding simple global template instantiations.
//

const clang::FunctionDecl* D1 = gCling->lookupFunctionProto(G, "d<int>", "int");
printf("D1: 0x%lx\n", (unsigned long) D1);
//CHECK: D1: 0x{{[1-9a-f][0-9a-f]*$}}
D1->print(llvm::outs());
//CHECK-NEXT: void d(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

const clang::FunctionDecl* D2 = gCling->lookupFunctionProto(G, "d<double>", "double");
printf("D2: 0x%lx\n", (unsigned long) D2);
//CHECK: D2: 0x{{[1-9a-f][0-9a-f]*$}}
D2->print(llvm::outs());
//CHECK-NEXT: void d(double v) {
//CHECK-NEXT:     double x = v;
//CHECK-NEXT: }

.rawInput 1
class B {
   void B_f() { int x = 1; }
   void B_g(int v) { int x = v; }
   void B_h(int vi, double vd) { int x = vi; double y = vd; }
   void B_j(int vi, int vj) { int x = vi; int y = vj; }
   void B_j(int vi, double vd) { int x = vi; double y = vd; }
   template <class T> void B_k(T v) { T x = v; }
};
class A : public B {
   void A_f() { int x = 1; }
   void A_g(int v) { int x = v; }
   void A_h(int vi, double vd) { int x = vi; double y = vd; }
   void A_j(int vi, int vj) { int x = vi; int y = vj; }
   void A_j(int vi, double vd) { int x = vi; double y = vd; }
   template <class T> void A_k(T v) { T x = v; }
};
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not, so we explicitly request the instantiations we are
//       going to lookup so they will be there to find.
template void A::A_k(int);
template void A::A_k(double);
template void A::B_k(int);
template void A::B_k(double);
.rawInput 0

const clang::Decl* class_A = gCling->lookupScope("A");
printf("class_A: 0x%lx\n", (unsigned long) class_A);
//CHECK: class_A: 0x{{[1-9a-f][0-9a-f]*$}}

const clang::Decl* class_B = gCling->lookupScope("B");
printf("class_B: 0x%lx\n", (unsigned long) class_B);
//CHECK-NEXT: class_B: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a member function taking no args.
//

const clang::FunctionDecl* class_A_F = gCling->lookupFunctionProto(class_A, "A_f", "");
printf("class_A_F: 0x%lx\n", (unsigned long) class_A_F);
//CHECK-NEXT: class_A_F: 0x{{[1-9a-f][0-9a-f]*$}}
class_A_F->print(llvm::outs());
//CHECK-NEXT: void A_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg.
//

const clang::FunctionDecl* func_A_g = gCling->lookupFunctionProto(class_A, "A_g", "int");
printf("func_A_g: 0x%lx\n", (unsigned long) func_A_g);
//CHECK: func_A_g: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_g->print(llvm::outs());
//CHECK-NEXT: void A_g(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int and a double argument.
//

const clang::FunctionDecl* func_A_h = gCling->lookupFunctionProto(class_A, "A_h", "int,double");
printf("func_A_h: 0x%lx\n", (unsigned long) func_A_h);
//CHECK: func_A_h: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_h->print(llvm::outs());
//CHECK-NEXT: void A_h(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding an overloaded member function.
//

const clang::FunctionDecl* func_A_j1 = gCling->lookupFunctionProto(class_A, "A_j", "int,int");
printf("func_A_j1: 0x%lx\n", (unsigned long) func_A_j1);
//CHECK: func_A_j1: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_j1->print(llvm::outs());
//CHECK-NEXT: void A_j(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* func_A_j2 = gCling->lookupFunctionProto(class_A, "A_j", "int,double");
printf("func_A_j2: 0x%lx\n", (unsigned long) func_A_j2);
//CHECK: func_A_j2: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_j2->print(llvm::outs());
//CHECK-NEXT: void A_j(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding simple member function template instantiations.
//

const clang::FunctionDecl* func_A_k1 = gCling->lookupFunctionProto(class_A, "A_k<int>", "int");
printf("func_A_k1: 0x%lx\n", (unsigned long) func_A_k1);
//CHECK: func_A_k1: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_k1->print(llvm::outs());
//CHECK-NEXT: void A_k(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

const clang::FunctionDecl* func_A_k2 = gCling->lookupFunctionProto(class_A, "A_k<double>", "double");
printf("func_A_k2: 0x%lx\n", (unsigned long) func_A_k2);
//CHECK: func_A_k2: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_k2->print(llvm::outs());
//CHECK-NEXT: void A_k(double v) {
//CHECK-NEXT:     double x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking no args in a base class.
//

const clang::FunctionDecl* func_B_F = gCling->lookupFunctionProto(class_A, "B_f", "");
printf("func_B_F: 0x%lx\n", (unsigned long) func_B_F);
//CHECK: func_B_F: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_F->print(llvm::outs());
//CHECK-NEXT: void B_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg in a base class.
//

const clang::FunctionDecl* func_B_G = gCling->lookupFunctionProto(class_A, "B_g", "int");
printf("func_B_G: 0x%lx\n", (unsigned long) func_B_G);
//CHECK: func_B_G: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_G->print(llvm::outs());
//CHECK-NEXT: void B_g(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int and a double argument
//  in a base class.
//

const clang::FunctionDecl* func_B_h = gCling->lookupFunctionProto(class_A, "B_h", "int,double");
printf("func_B_h: 0x%lx\n", (unsigned long) func_B_h);
//CHECK: func_B_h: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_h->print(llvm::outs());
//CHECK-NEXT: void B_h(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding an overloaded member function in a base class.
//

const clang::FunctionDecl* func_B_j1 = gCling->lookupFunctionProto(class_A, "B_j", "int,int");
printf("func_B_j1: 0x%lx\n", (unsigned long) func_B_j1);
//CHECK: func_B_j1: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_j1->print(llvm::outs());
//CHECK-NEXT: void B_j(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* func_B_j2 = gCling->lookupFunctionProto(class_A, "B_j", "int,double");
printf("func_B_j2: 0x%lx\n", (unsigned long) func_B_j2);
//CHECK: func_B_j2: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_j2->print(llvm::outs());
//CHECK-NEXT: void B_j(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding simple member function template instantiations in a base class.
//

const clang::FunctionDecl* func_B_k1 = gCling->lookupFunctionProto(class_A, "B_k<int>", "int");
printf("func_B_k1: 0x%lx\n", (unsigned long) func_B_k1);
//CHECK: func_B_k1: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_k1->print(llvm::outs());
//CHECK-NEXT: void B_k(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

const clang::FunctionDecl* func_B_k2 = gCling->lookupFunctionProto(class_A, "B_k<double>", "double");
printf("func_B_k2: 0x%lx\n", (unsigned long) func_B_k2);
//CHECK: func_B_k2: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_k2->print(llvm::outs());
//CHECK-NEXT: void B_k(double v) {
//CHECK-NEXT:     double x = v;
//CHECK-NEXT: }

//
//  One final check to make sure we are at the right line in the output.
//

"abc"
//CHECK: (const char [4]) @0x{{[0-9a-f]+}}
<|endoftext|>


<commit_before>// Created by filipecn on 3/3/18.
#include <circe/circe.h>

#define WIDTH 800
#define HEIGHT 800

const char *fs = "#version 440 core\n"
                 "out vec4 outColor;"
                 "in vec2 texCoord;"
                 "uniform sampler2D tex;"
                 "void main() {"
                 "ivec2 texel = ivec2(gl_FragCoord.xy);"
                 "outColor = (texelFetchOffset(tex, texel, 0, ivec2(0, 0)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(1, 1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(0, 1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(-1, 1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(-1, 0)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(1, 0)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(-1, -1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(1, -1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(0, -1))) / 9.0;"
                 "}";

int main() {
  circe::gl::SceneApp<> app(WIDTH, HEIGHT, "Post Effects Example");
  app.init();
  app.viewports[0].renderer->addEffect(new circe::gl::GammaCorrection());
  //  app.viewports[0].renderer->addEffect(new circe::FXAA());
  //  app.viewports[0].renderer->addEffect(new circe::PostEffect(
  //      new circe::Shader(circe_NO_VAO_VS, nullptr, fs)));
  std::shared_ptr<circe::gl::CartesianGrid> grid(
      app.scene.add<circe::gl::CartesianGrid>(new circe::gl::CartesianGrid(5)));
  app.run();
  return 0;
}<commit_msg>fix circe example<commit_after>// Created by filipecn on 3/3/18.
#include <circe/circe.h>

#define WIDTH 800
#define HEIGHT 800

const char *fs = "#version 440 core\n"
                 "out vec4 outColor;"
                 "in vec2 texCoord;"
                 "uniform sampler2D tex;"
                 "void main() {"
                 "ivec2 texel = ivec2(gl_FragCoord.xy);"
                 "outColor = (texelFetchOffset(tex, texel, 0, ivec2(0, 0)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(1, 1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(0, 1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(-1, 1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(-1, 0)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(1, 0)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(-1, -1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(1, -1)) +"
                 "texelFetchOffset(tex, texel, 0, ivec2(0, -1))) / 9.0;"
                 "}";

int main() {
  circe::gl::SceneApp<> app(WIDTH, HEIGHT, "Post Effects Example");
  app.init();
  app.viewports[0].renderer->addEffect(new circe::gl::GammaCorrection());
  //  app.viewports[0].renderer->addEffect(new circe::FXAA());
  //  app.viewports[0].renderer->addEffect(new circe::PostEffect(
  //      new circe::Shader(circe_NO_VAO_VS, nullptr, fs)));
  app.scene.add(new circe::gl::CartesianGrid(5));
  app.run();
  return 0;
}<|endoftext|>