<commit_before>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <cstdint>
#include <deque>
#include <mutex>
#include <tuple>
#include <utility>
#include "raz/callback.hpp"
#include "raz/memory.hpp"
#include "raz/serialization.hpp"

namespace raz
{
	typedef uint32_t EventType;

	template<unsigned N>
	struct EventNamedParam
	{
		static const unsigned ParamNumber = N;
	};

	template<EventType Type, class... Params>
	class Event : public std::tuple<Params...>
	{
	public:
		typedef Callback<Event> Callback;

		class CallbackSystem : public raz::CallbackSystem<Event>
		{
		public:
			CallbackSystem() = default;

			explicit CallbackSystem(IMemoryPool& memory) :
				raz::CallbackSystem<Event>(memory)
			{
			}

			CallbackSystem(CallbackSystem&& other) :
				raz::CallbackSystem<Event>(other)
			{
			}

			static constexpr EventType getEventType()
			{
				return Event::getType();
			}

			template<class Serializer>
			raz::EnableSerializer<Serializer> handleSerialized(Serializer& serializer)
			{
				Event e(serializer);
				handle(e);
			}
		};

		template<class _, class Serializer = EnableSerializer<_>>
		explicit Event(Serializer& serializer)
		{
			if (serializer.getMode() == ISerializer::Mode::DESERIALIZE)
				_serialize<0>(serializer);
			else
				throw SerializationError();
		}

		Event(Params... params) :
			std::tuple<Params...>(std::forward<Params>(params)...)
		{
		}

		static constexpr EventType getType()
		{
			return Type;
		}

		template<size_t N>
		auto get() -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<size_t N>
		auto get() const -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		auto get() -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		auto get() const -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		void get(NamedParam*& tag)
		{
			tag = &get<N>();
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		void get(const NamedParam*& tag) const
		{
			tag = &get<N>();
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> operator()(Serializer& serializer)
		{
			_serialize<0>(serializer);
		}

	private:
		template<size_t N, class Serializer>
		std::enable_if_t<(N < sizeof...(Params))> _serialize(Serializer& serializer)
		{
			serializer(get<N>());
			_serialize<N + 1>(serializer);
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N >= sizeof...(Params))> _serialize(Serializer&)
		{
		}
	};

	namespace literal
	{
		static constexpr uint64_t stringhash(const char* str, const uint64_t h = 5381)
		{
			return (str[0] == 0) ? h : stringhash(&str[1], h * 33 + str[0]);
		}

		constexpr EventType operator"" _event(const char* evt, size_t)
		{
			return (EventType)stringhash(evt);
		}
	}

	template<class Event>
	class EventQueue
	{
	public:
		EventQueue() = default;

		explicit EventQueue(IMemoryPool& memory) : m_queue(memory)
		{
		}

		EventQueue(EventQueue&& other) : m_queue(std::move(other.m_queue))
		{
		}

		static constexpr EventType getEventType()
		{
			return Event::getType();
		}

		template<class... Params>
		auto enqueue(Params... params) -> decltype(void(new Event(std::forward<Params>(params)...)))
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);
			m_queue.emplace_back(std::forward<Params>(params)...);
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> enqueueSerialized(Serializer& serializer)
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);
			m_queue.emplace_back(serializer);
		}

		template<class Handler>
		void dequeue(Handler& handler)
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);

			while (!m_queue.empty())
			{
				handler.handle(m_queue.front());
				m_queue.pop_front();
			}
		}

		template<class Handler>
		void dequeue(Handler& handler, unsigned n)
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);
			unsigned count = 0;

			while (!m_queue.empty() && count < n)
			{
				handler.handle(m_queue.front());
				m_queue.pop_front();
				++count;
			}
		}

		void clear()
		{
			m_queue.clear();
		}

	private:
		std::recursive_mutex m_lock;
		std::deque<Event, raz::Allocator<Event>> m_queue;
	};

	template<class... Events>
	class EventQueueSystem
	{
	public:
		EventQueueSystem() = default;

		explicit EventQueueSystem(IMemoryPool& memory) :
			m_queues( (sizeof(Events), memory)... )
		{
		}

		EventQueueSystem(EventQueueSystem&& other) :
			m_queues(std::move(other.m_queues))
		{
		}

		template<EventType Type, class... Params>
		void enqueue(Params... params)
		{
			_enqueue<Type, 0>(std::forward<Params>(params)...);
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> enqueueSerialized(EventType type, Serializer& serializer)
		{
			_enqueueSerialized<0>(type, serializer);
		}

		template<class Handler>
		void dequeue(Handler& handler) // Event::CallbackSystem, EventDispatcher, etc
		{
			_dequeue<0>(handler);
		}

		void clear()
		{
			_clear<0>();
		}

	private:
		std::tuple<EventQueue<Events>...> m_queues;

		template<EventType Type>
		void _enqueue(...)
		{
		}

		template<EventType Type, class Queue, class... Params>
		auto _enqueue(Queue& queue, Params... params) -> decltype(queue.enqueue(std::forward<Params>(params)...))
		{
			if (Queue::getEventType() == Type)
				queue.enqueue(std::forward<Params>(params)...);
		}

		template<EventType Type, size_t N, class... Params>
		std::enable_if_t<(N < sizeof...(Events))> _enqueue(Params... params)
		{
			_enqueue<Type>(std::get<N>(m_queues), std::forward<Params>(params)...);
			_enqueue<Type, N + 1>(std::forward<Params>(params)...);
		}

		template<EventType Type, size_t N, class... Params>
		std::enable_if_t<(N >= sizeof...(Events))> _enqueue(Params...)
		{
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N < sizeof...(Events))> _enqueueSerialized(EventType type, Serializer& serializer)
		{
			auto& queue = std::get<N>(m_queues);
			if (queue.getEventType() == type)
				queue.enqueueSerialized(serializer);

			_enqueueSerialized<N + 1>(type, serializer);
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N >= sizeof...(Events))> _enqueueSerialized(EventType, Serializer&)
		{
		}

		void _dequeue(...)
		{
		}

		template<class Queue, class Handler>
		auto _dequeue(Queue& queue, Handler& handler) -> decltype(queue.dequeue(handler))
		{
			queue.dequeue(handler);
		}

		template<size_t N, class Handler>
		std::enable_if_t<(N < sizeof...(Events))> _dequeue(Handler& handler)
		{
			_dequeue(std::get<N>(m_queues), handler);
			_dequeue<N + 1>(handler);
		}

		template<size_t N, class Handler>
		std::enable_if_t<(N >= sizeof...(Events))> _dequeue(Handler&)
		{
		}

		template<size_t N>
		std::enable_if_t<(N < sizeof...(Events))> _clear()
		{
			std::get<N>(m_queues).clear();
			_clear<N + 1>();
		}

		template<size_t N>
		std::enable_if_t<(N >= sizeof...(Events))> _clear()
		{
		}
	};

	template<class... Events>
	class EventDispatcher
	{
	public:
		EventDispatcher(typename Events::CallbackSystem&... callback_system) : // CallbackSystem references must not become invalid
			m_callback_systems((&callback_system)...)
		{
		}

		EventDispatcher(const EventDispatcher& other) :
			m_callback_systems(other.m_callback_systems)
		{
		}

		template<class Event>
		void handle(const Event& e)
		{
			_handle<0>(e);
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> handleSerialized(EventType type, Serializer& s)
		{
			_handleSerialized<0>(type, s);
		}

	private:
		std::tuple<typename Events::CallbackSystem*...> m_callback_systems;

		void _handle(...)
		{
		}

		template<class CallbackSystem, class Event>
		auto _handle(CallbackSystem* handler, const Event& e) -> decltype(handler->handle(e))
		{
			handler->handle(e);
		}

		template<size_t N, class Event>
		std::enable_if_t<(N < sizeof...(Events))> _handle(const Event& e)
		{
			auto handler = std::get<N>(m_callback_systems);
			if (handler->getEventType() == e.getType())
				_handle(handler, e);
		}

		template<size_t N, class Event>
		std::enable_if_t<(N >= sizeof...(Events))> _handle(const Event&)
		{
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N < sizeof...(Events))> _handleSerialized(EventType type, Serializer& s)
		{
			auto handler = std::get<N>(m_callback_systems);
			if (handler->getEventType() == type)
				handler->handleSerialized<Serializer>(s);

			_handleSerialized<N + 1>(type, s);
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N >= sizeof...(Events))> _handleSerialized(EventType, Serializer&)
		{
		}
	};

	template<class... Events>
	class EventSystem : public EventDispatcher<Events...>
	{
	public:
		EventSystem() :
			EventDispatcher(std::get<typename Events::CallbackSystem>(m_callback_systems)...)
		{
		}

		explicit EventSystem(IMemoryPool& memory) :
			EventDispatcher(std::get<typename Events::CallbackSystem>(m_callback_systems)...)
			m_callback_systems( (sizeof(Events), memory)... )
		{
		}

		EventSystem(EventSystem&& other) :
			EventDispatcher(std::get<typename Events::CallbackSystem>(m_callback_systems)...)
			m_callback_systems(std::move(other.m_callback_systems))
		{
		}

		template<class Event>
		typename Event::CallbackSystem& access(Event* = nullptr)
		{
			return std::get<typename Event::CallbackSystem>(m_callback_systems);
		}

		template<class Callback>
		typename Callback::ValueType::CallbackSystem& access(Callback* = nullptr)
		{
			return std::get<typename Callback::ValueType::CallbackSystem>(m_callback_systems);
		}

	private:
		std::tuple<typename Events::CallbackSystem...> m_callback_systems;
	};
}
<commit_msg>Minor changes<commit_after>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <cstdint>
#include <deque>
#include <mutex>
#include <tuple>
#include <utility>
#include "raz/callback.hpp"
#include "raz/memory.hpp"
#include "raz/serialization.hpp"

namespace raz
{
	typedef uint32_t EventType;

	template<unsigned N>
	struct EventNamedParam
	{
		static const unsigned ParamNumber = N;
	};

	template<EventType Type, class... Params>
	class Event : public std::tuple<Params...>
	{
	public:
		typedef Callback<Event> Callback;

		class CallbackSystem : public raz::CallbackSystem<Event>
		{
		public:
			CallbackSystem() = default;

			explicit CallbackSystem(IMemoryPool& memory) :
				raz::CallbackSystem<Event>(memory)
			{
			}

			CallbackSystem(CallbackSystem&& other) :
				raz::CallbackSystem<Event>(other)
			{
			}

			static constexpr EventType getEventType()
			{
				return Event::getType();
			}

			template<class Serializer>
			raz::EnableSerializer<Serializer> handleSerialized(Serializer& serializer)
			{
				Event e(serializer);
				handle(e);
			}
		};

		template<class _, class Serializer = EnableSerializer<_>>
		explicit Event(Serializer& serializer)
		{
			if (serializer.getMode() == ISerializer::Mode::DESERIALIZE)
				_serialize<0>(serializer);
			else
				throw SerializationError();
		}

		Event(Params... params) :
			std::tuple<Params...>(std::forward<Params>(params)...)
		{
		}

		static constexpr EventType getType()
		{
			return Type;
		}

		template<size_t N>
		auto get() -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<size_t N>
		auto get() const -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		auto get() -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		auto get() const -> decltype(std::get<N>(*this))
		{
			return std::get<N>(*this);
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		void get(NamedParam*& tag)
		{
			tag = &get<N>();
		}

		template<class NamedParam, size_t N = NamedParam::ParamNumber>
		void get(const NamedParam*& tag) const
		{
			tag = &get<N>();
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> operator()(Serializer& serializer)
		{
			_serialize<0>(serializer);
		}

	private:
		template<size_t N, class Serializer>
		std::enable_if_t<(N < sizeof...(Params))> _serialize(Serializer& serializer)
		{
			serializer(get<N>());
			_serialize<N + 1>(serializer);
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N >= sizeof...(Params))> _serialize(Serializer&)
		{
		}
	};

	namespace literal
	{
		inline constexpr uint64_t stringhash(const char* str, const uint64_t h = 5381)
		{
			return (str[0] == 0) ? h : stringhash(&str[1], h * 33 + str[0]);
		}

		inline constexpr EventType operator"" _event(const char* evt, size_t)
		{
			return (EventType)stringhash(evt);
		}
	}

	template<class Event>
	class EventQueue
	{
	public:
		EventQueue(IMemoryPool* memory = nullptr) : m_queue(memory)
		{
		}

		EventQueue(EventQueue&& other) : m_queue(std::move(other.m_queue))
		{
		}

		static constexpr EventType getEventType()
		{
			return Event::getType();
		}

		template<class... Params>
		auto enqueue(Params... params) -> decltype(void(new Event(std::forward<Params>(params)...)))
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);
			m_queue.emplace_back(std::forward<Params>(params)...);
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> enqueueSerialized(Serializer& serializer)
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);
			m_queue.emplace_back(serializer);
		}

		template<class Handler>
		void dequeue(Handler& handler)
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);

			while (!m_queue.empty())
			{
				handler.handle(m_queue.front());
				m_queue.pop_front();
			}
		}

		template<class Handler>
		void dequeue(Handler& handler, unsigned n)
		{
			std::lock_guard<decltype(m_lock)> guard(m_lock);
			unsigned count = 0;

			while (!m_queue.empty() && count < n)
			{
				handler.handle(m_queue.front());
				m_queue.pop_front();
				++count;
			}
		}

		void clear()
		{
			m_queue.clear();
		}

	private:
		std::recursive_mutex m_lock;
		std::deque<Event, raz::Allocator<Event>> m_queue;
	};

	template<class... Events>
	class EventQueueSystem
	{
	public:
		explicit EventQueueSystem(IMemoryPool* memory = nullptr) :
			m_queues( (sizeof(Events), memory)... )
		{
		}

		EventQueueSystem(EventQueueSystem&& other) :
			m_queues(std::move(other.m_queues))
		{
		}

		template<EventType Type, class... Params>
		void enqueue(Params... params)
		{
			_enqueue<Type, 0>(std::forward<Params>(params)...);
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> enqueueSerialized(EventType type, Serializer& serializer)
		{
			_enqueueSerialized<0>(type, serializer);
		}

		template<class Handler>
		void dequeue(Handler& handler) // Event::CallbackSystem, EventDispatcher, etc
		{
			_dequeue<0>(handler);
		}

		void clear()
		{
			_clear<0>();
		}

	private:
		std::tuple<EventQueue<Events>...> m_queues;

		template<EventType Type>
		void _enqueue(...)
		{
		}

		template<EventType Type, class Queue, class... Params>
		auto _enqueue(Queue& queue, Params... params) -> decltype(queue.enqueue(std::forward<Params>(params)...))
		{
			if (Queue::getEventType() == Type)
				queue.enqueue(std::forward<Params>(params)...);
		}

		template<EventType Type, size_t N, class... Params>
		std::enable_if_t<(N < sizeof...(Events))> _enqueue(Params... params)
		{
			_enqueue<Type>(std::get<N>(m_queues), std::forward<Params>(params)...);
			_enqueue<Type, N + 1>(std::forward<Params>(params)...);
		}

		template<EventType Type, size_t N, class... Params>
		std::enable_if_t<(N >= sizeof...(Events))> _enqueue(Params...)
		{
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N < sizeof...(Events))> _enqueueSerialized(EventType type, Serializer& serializer)
		{
			auto& queue = std::get<N>(m_queues);
			if (queue.getEventType() == type)
				queue.enqueueSerialized(serializer);

			_enqueueSerialized<N + 1>(type, serializer);
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N >= sizeof...(Events))> _enqueueSerialized(EventType, Serializer&)
		{
		}

		void _dequeue(...)
		{
		}

		template<class Queue, class Handler>
		auto _dequeue(Queue& queue, Handler& handler) -> decltype(queue.dequeue(handler))
		{
			queue.dequeue(handler);
		}

		template<size_t N, class Handler>
		std::enable_if_t<(N < sizeof...(Events))> _dequeue(Handler& handler)
		{
			_dequeue(std::get<N>(m_queues), handler);
			_dequeue<N + 1>(handler);
		}

		template<size_t N, class Handler>
		std::enable_if_t<(N >= sizeof...(Events))> _dequeue(Handler&)
		{
		}

		template<size_t N>
		std::enable_if_t<(N < sizeof...(Events))> _clear()
		{
			std::get<N>(m_queues).clear();
			_clear<N + 1>();
		}

		template<size_t N>
		std::enable_if_t<(N >= sizeof...(Events))> _clear()
		{
		}
	};

	template<class... Events>
	class EventDispatcher
	{
	public:
		EventDispatcher(typename Events::CallbackSystem&... callback_system) : // CallbackSystem references must not become invalid
			m_callback_systems((&callback_system)...)
		{
		}

		EventDispatcher(const EventDispatcher& other) :
			m_callback_systems(other.m_callback_systems)
		{
		}

		template<class Event>
		void handle(const Event& e)
		{
			_handle<0>(e);
		}

		template<class Serializer>
		raz::EnableSerializer<Serializer> handleSerialized(EventType type, Serializer& s)
		{
			_handleSerialized<0>(type, s);
		}

	private:
		std::tuple<typename Events::CallbackSystem*...> m_callback_systems;

		void _handle(...)
		{
		}

		template<class CallbackSystem, class Event>
		auto _handle(CallbackSystem* handler, const Event& e) -> decltype(handler->handle(e))
		{
			handler->handle(e);
		}

		template<size_t N, class Event>
		std::enable_if_t<(N < sizeof...(Events))> _handle(const Event& e)
		{
			auto handler = std::get<N>(m_callback_systems);
			if (handler->getEventType() == e.getType())
				_handle(handler, e);
		}

		template<size_t N, class Event>
		std::enable_if_t<(N >= sizeof...(Events))> _handle(const Event&)
		{
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N < sizeof...(Events))> _handleSerialized(EventType type, Serializer& s)
		{
			auto handler = std::get<N>(m_callback_systems);
			if (handler->getEventType() == type)
				handler->handleSerialized<Serializer>(s);

			_handleSerialized<N + 1>(type, s);
		}

		template<size_t N, class Serializer>
		std::enable_if_t<(N >= sizeof...(Events))> _handleSerialized(EventType, Serializer&)
		{
		}
	};

	template<class... Events>
	class EventSystem : public EventDispatcher<Events...>
	{
	public:
		EventSystem() :
			EventDispatcher(std::get<typename Events::CallbackSystem>(m_callback_systems)...)
		{
		}

		explicit EventSystem(IMemoryPool& memory) :
			EventDispatcher(std::get<typename Events::CallbackSystem>(m_callback_systems)...)
			m_callback_systems( (sizeof(Events), memory)... )
		{
		}

		EventSystem(EventSystem&& other) :
			EventDispatcher(std::get<typename Events::CallbackSystem>(m_callback_systems)...)
			m_callback_systems(std::move(other.m_callback_systems))
		{
		}

		template<class Event>
		typename Event::CallbackSystem& access(Event* = nullptr)
		{
			return std::get<typename Event::CallbackSystem>(m_callback_systems);
		}

		template<class Callback>
		typename Callback::ValueType::CallbackSystem& access(Callback* = nullptr)
		{
			return std::get<typename Callback::ValueType::CallbackSystem>(m_callback_systems);
		}

	private:
		std::tuple<typename Events::CallbackSystem...> m_callback_systems;
	};
}
<|endoftext|>


<commit_before>#include "player.h"
#include "subjectblock.h"
#include "types.h"
#include <iostream>
#include <algorithm>
#include <QDebug>
#include "board.h"
#include <QtGlobal>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include "localgame.h"
#include "sellpopup.h"
#include <QMediaPlayer>
#include <QFileInfo>
#include <QDir>
#define NUMBER_OF_BLOCKS 32
#define NEXT_POS(current_pos) ((current_pos + 1) % 32)

using namespace std;

Player::Player(QGameItem* parent,int _id) : QGameItem(parent)
{
    //randomly determine CharacterType
    int n = rand() % 5;
    switch(n){
    case 0:
        character_type = CharacterType::LOL;
        break;
    case 1:
        character_type = CharacterType::GENIUS;
        break;
    case 2:
        character_type = CharacterType::HARD_WORKER;
        break;
    case 3:
        character_type = CharacterType::OUTSIDER;
        break;
    case 4:
        character_type = CharacterType::ALCOHOLIC;
    }

    id = _id;
    name = "";
    position = 0;

    energy = 1000;
    if(character_type == CharacterType::GENIUS)
        energy += 200;

    bankrupt = false;
    mobile = true;
    immobile_penalty = 0;
    plural = false;

    character_type = CharacterType::NONE;
    //totalownsubjectenergy=0;//지우고 동적으로 계산하라

    //initialize map
    using namespace SubjectType;
    registered[BIO] = 0;
    registered[CHEM] = 0;
    registered[CSED] = 0;
    registered[EE] = 0;
    registered[MATH] = 0;
    registered[ME] = 0;
    registered[IME] = 0;
    registered[PHYS] = 0;

    switch(_id){
    case 1:
        player_color = QString("org");
        break;
    case 2:
        player_color = QString("blue");
        break;
    }

    // end initialize
    qDebug() << "Player Created" << endl;
}

Player::~Player()
{
    //delete own_blocks;

    qDebug() << "Player Destroyed" << endl;
}

// Accessor Methods
int Player::getPosition() const
{
    return position;
}

QPointF Player::adjustCoord(QPointF &coord){
    return coord;
}

bool Player::isBankrupt() const
{
    return bankrupt;
}

bool Player::isMobile() const
{
    return mobile;
}

int Player::getEnergy() const
{
    return energy;
}

int Player::getPenalty() const
{
    return immobile_penalty;
}

bool Player::isPlural() const
{
    return plural;
}

CharacterType::Type Player::getType() const
{
    return character_type;
}

list<Block*> Player::getBlocks() const
{
    return own_blocks;
}

// Methods
void Player::setEnergy(int energy)
{
    this->energy = energy;
    emit energyChanged(this->energy);
}

void Player::setPlural(bool plural)
{
    this->plural = plural;
}

void Player::setBankrupt()
{
    setEnergy(0);
    bankrupt = true;
}

// set player to stay mouindo
// parm: how long to stay in mouindo
void Player::setMouindo(int penalty)
{
    this->immobile_penalty = penalty;
    mobile = false;
}

void Player::setMobile(bool mobile){
    this->mobile = mobile;
    immobile_penalty = 0;
}

void Player::escapeAttempt(){
    immobile_penalty--;
    if(immobile_penalty==0)
        mobile = true;
}

//probably unused forever...
bool Player::escapeMouindo()
{
    if(mobile)
        return true;

    else {

        if(immobile_penalty == 0) {
            mobile = true;
            return true;
        }

        else {
            // roll a dice
            immobile_penalty--;
            return false;
        }
    }
}

void Player::walkBy(int steps)
{
    using namespace BlockCoords;
    LocalGame::getInst()->setGameState(LocalGameState::PLAYER_MOVING);
    const int step_interval = 300; //0.1 seconds
    int current_pos = position;
    int next_pos;

    QSequentialAnimationGroup * seq_animation_group
            = new QSequentialAnimationGroup;

    //add sleep animation
    QPropertyAnimation * sleep
            = new QPropertyAnimation(this,"pos");
    sleep->setDuration(1800);
    //don't move
    sleep->setStartValue(block_coord[current_pos]);
    sleep->setEndValue(block_coord[current_pos]);
    seq_animation_group->addAnimation(sleep);

    while(steps){
        next_pos = NEXT_POS(current_pos);
        QPropertyAnimation * step_animation
                = new QPropertyAnimation(this,"pos");
        step_animation->setDuration(step_interval);
        step_animation->setStartValue(block_coord[current_pos]);
        step_animation->setEndValue(block_coord[next_pos]);
        step_animation->setEasingCurve(QEasingCurve::InOutQuint);
        connect(step_animation,SIGNAL(finished()),this,SLOT(stepForward()));
        seq_animation_group->addAnimation(step_animation);
        steps--; //decrease one step
        current_pos = next_pos;
        if(current_pos == 0){
            //maybe add animation for gaining energy
            giveSalary();
            QMediaPlayer* player = new QMediaPlayer();
            player->setMedia(QUrl::fromLocalFile(QFileInfo("sound/coin.wav").absoluteFilePath()));
            player->setVolume(100);
            player->play();
        }
    }
    seq_animation_group->start(QAbstractAnimation::DeleteWhenStopped);

    connect(seq_animation_group,SIGNAL(finished()),this,SLOT(arrived()));
    //position = current_pos;
}

void Player::jumpTo(int block_num){
    using namespace BlockCoords;
    LocalGame::getInst()->setGameState(LocalGameState::PLAYER_MOVING);
    QPointF target = block_coord[block_num];
    QPropertyAnimation * step_animation
            = new QPropertyAnimation(this,"pos");
    step_animation->setDuration(2000);
    step_animation->setStartValue(block_coord[getPosition()]);
    step_animation->setEndValue(target);
    step_animation->setEasingCurve(QEasingCurve::InOutQuint);
    step_animation->start(QAbstractAnimation::DeleteWhenStopped);

    connect(step_animation,SIGNAL(finished()),this,SLOT(arrived()));
    position = block_num;
}

void Player::stepForward(){
    position = NEXT_POS(position);
}

void Player::arrived(){
    qDebug() << "arrived at:"<<position;
    emit playerArrived(this);
}

bool Player::hasBlock(Block* block)
{
    // subject block check
    if(block->getType() != BlockType::SUBJECT) {
        qDebug() << "This is not a Subject Block!";
        return false;
    }

    list<Block*>::iterator finder = own_blocks.end();
    finder = find(own_blocks.begin(), own_blocks.end(), block);

    // no matching
    if(finder == own_blocks.end())
        return false;
    else
        return true;
}

void Player::addBlock(Block *block)
{
    SubjectBlock * subj_block = dynamic_cast<SubjectBlock*>(block);
    subj_block->setOwner(this);
    registered.find(((SubjectBlock*)block)->getDept())->second++;
    own_blocks.push_back(block);
}

void Player::removeBlock(Block *block)
{
    if(!hasBlock(block)) {
        qDebug() << "You don't have that block. Check Again!";
        return;
    }
    SubjectBlock * sblock = dynamic_cast<SubjectBlock*>(block);
    sblock->setGrade(SubjectBlock::NONE);
    registered.find(((SubjectBlock*)block)->getDept())->second--;
    own_blocks.remove(block);
}

void Player::giveSalary()
{
    qDebug() << "Player " << id << " received salary";

    if(character_type == CharacterType::HARD_WORKER)
        energy += 150;
    else
        energy += 100;

    emit energyChanged(this->energy);
}

bool Player::checkWinStatus()
{
    int majored = 0;

    for(map<SubjectType::Type, int>::iterator i = registered.begin(); i != registered.end(); i++) {
        if(i->second == 3)
            majored ++;
    }

    if(plural && majored >= 2)
        return true;
    else if (!plural && majored >= 1)
        return true;
    else
        return false;
}

void Player::payEnergy(int payenergy)
{
    if(energy >= payenergy)
        energy-=payenergy;
    else{
        if(getAssetValue() >= payenergy){
            Sellpopup * popup = new Sellpopup;
            popup->show();
        }
        else
            setBankrupt();
    }
    emit energyChanged(this->energy);
}
void Player::giveEnergy(int paidenergy){
    energy+=paidenergy;
    emit energyChanged(this->energy);
}

int Player::getId() const {
    return id;
}

void Player::setType(CharacterType::Type type) {
    character_type = type;
}

int Player::getAssetValue() {

    int asset = 0;

    if(own_blocks.empty()) {
        qDebug() << "Player has nothing!";
        asset = 0;
    }
    else {
        for(list<Block*>::iterator itor = own_blocks.begin(); itor != own_blocks.end(); itor++) {
           asset += dynamic_cast<SubjectBlock*>(*itor)->getSellCost();
        }
    }
    return asset;
}

void Player::animatePlayerImage(int frame){
    QString filename = QString(":/images/ingame/character/");

    int zone = position /8 ;

    if(zone == 0){
        filename += QString("top_up_id_");
    }
    else if(zone ==1){
        filename += QString("top_right_id_");
    }
    else if(zone ==2){
        filename += QString("top_down_id_");
    }
    else {
        filename += QString("top_right_id_");
    }

    filename += player_color + QString("_");

    LocalGame * game_inst = LocalGame::getInst();

    if(game_inst->getGameState() == LocalGameState::PLAYER_MOVING
            && game_inst->getCurrentPlayer() == this)
        filename += QString("walk_");
    else
        filename += QString("stand_");

    filename += QString::number(frame).rightJustified(3,'0') + QString(".png");

    //qDebug() << filename;

    QImage image(filename);

    QTransform rotate;
    rotate.rotate(180);

    if(zone == 3)
        image = image.mirrored(true,false);

    setPixmap(QPixmap::fromImage(image));
}
<commit_msg>Player: give salary at the moment when it passes dormitory<commit_after>#include "player.h"
#include "subjectblock.h"
#include "types.h"
#include <iostream>
#include <algorithm>
#include <QDebug>
#include "board.h"
#include <QtGlobal>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include "localgame.h"
#include "sellpopup.h"
#include <QMediaPlayer>
#include <QFileInfo>
#include <QDir>
#define NUMBER_OF_BLOCKS 32
#define NEXT_POS(current_pos) ((current_pos + 1) % 32)

using namespace std;

Player::Player(QGameItem* parent,int _id) : QGameItem(parent)
{
    //randomly determine CharacterType
    int n = rand() % 5;
    switch(n){
    case 0:
        character_type = CharacterType::LOL;
        break;
    case 1:
        character_type = CharacterType::GENIUS;
        break;
    case 2:
        character_type = CharacterType::HARD_WORKER;
        break;
    case 3:
        character_type = CharacterType::OUTSIDER;
        break;
    case 4:
        character_type = CharacterType::ALCOHOLIC;
    }

    id = _id;
    name = "";
    position = 0;

    energy = 1000;
    if(character_type == CharacterType::GENIUS)
        energy += 200;

    bankrupt = false;
    mobile = true;
    immobile_penalty = 0;
    plural = false;

    character_type = CharacterType::NONE;
    //totalownsubjectenergy=0;//지우고 동적으로 계산하라

    //initialize map
    using namespace SubjectType;
    registered[BIO] = 0;
    registered[CHEM] = 0;
    registered[CSED] = 0;
    registered[EE] = 0;
    registered[MATH] = 0;
    registered[ME] = 0;
    registered[IME] = 0;
    registered[PHYS] = 0;

    switch(_id){
    case 1:
        player_color = QString("org");
        break;
    case 2:
        player_color = QString("blue");
        break;
    }

    // end initialize
    qDebug() << "Player Created" << endl;
}

Player::~Player()
{
    //delete own_blocks;

    qDebug() << "Player Destroyed" << endl;
}

// Accessor Methods
int Player::getPosition() const
{
    return position;
}

QPointF Player::adjustCoord(QPointF &coord){
    return coord;
}

bool Player::isBankrupt() const
{
    return bankrupt;
}

bool Player::isMobile() const
{
    return mobile;
}

int Player::getEnergy() const
{
    return energy;
}

int Player::getPenalty() const
{
    return immobile_penalty;
}

bool Player::isPlural() const
{
    return plural;
}

CharacterType::Type Player::getType() const
{
    return character_type;
}

list<Block*> Player::getBlocks() const
{
    return own_blocks;
}

// Methods
void Player::setEnergy(int energy)
{
    this->energy = energy;
    emit energyChanged(this->energy);
}

void Player::setPlural(bool plural)
{
    this->plural = plural;
}

void Player::setBankrupt()
{
    setEnergy(0);
    bankrupt = true;
}

// set player to stay mouindo
// parm: how long to stay in mouindo
void Player::setMouindo(int penalty)
{
    this->immobile_penalty = penalty;
    mobile = false;
}

void Player::setMobile(bool mobile){
    this->mobile = mobile;
    immobile_penalty = 0;
}

void Player::escapeAttempt(){
    immobile_penalty--;
    if(immobile_penalty==0)
        mobile = true;
}

//probably unused forever...
bool Player::escapeMouindo()
{
    if(mobile)
        return true;

    else {

        if(immobile_penalty == 0) {
            mobile = true;
            return true;
        }

        else {
            // roll a dice
            immobile_penalty--;
            return false;
        }
    }
}

void Player::walkBy(int steps)
{
    using namespace BlockCoords;
    LocalGame::getInst()->setGameState(LocalGameState::PLAYER_MOVING);
    const int step_interval = 300; //0.1 seconds
    int current_pos = position;
    int next_pos;

    QSequentialAnimationGroup * seq_animation_group
            = new QSequentialAnimationGroup;

    //add sleep animation
    QPropertyAnimation * sleep
            = new QPropertyAnimation(this,"pos");
    sleep->setDuration(1800);
    //don't move
    sleep->setStartValue(block_coord[current_pos]);
    sleep->setEndValue(block_coord[current_pos]);
    seq_animation_group->addAnimation(sleep);

    while(steps){
        next_pos = NEXT_POS(current_pos);
        QPropertyAnimation * step_animation
                = new QPropertyAnimation(this,"pos");
        step_animation->setDuration(step_interval);
        step_animation->setStartValue(block_coord[current_pos]);
        step_animation->setEndValue(block_coord[next_pos]);
        step_animation->setEasingCurve(QEasingCurve::InOutQuint);
        connect(step_animation,SIGNAL(finished()),this,SLOT(stepForward()));
        seq_animation_group->addAnimation(step_animation);
        steps--; //decrease one step
        current_pos = next_pos;

    }
    seq_animation_group->start(QAbstractAnimation::DeleteWhenStopped);

    connect(seq_animation_group,SIGNAL(finished()),this,SLOT(arrived()));
    //position = current_pos;
}

void Player::jumpTo(int block_num){
    using namespace BlockCoords;
    LocalGame::getInst()->setGameState(LocalGameState::PLAYER_MOVING);
    QPointF target = block_coord[block_num];
    QPropertyAnimation * step_animation
            = new QPropertyAnimation(this,"pos");
    step_animation->setDuration(2000);
    step_animation->setStartValue(block_coord[getPosition()]);
    step_animation->setEndValue(target);
    step_animation->setEasingCurve(QEasingCurve::InOutQuint);
    step_animation->start(QAbstractAnimation::DeleteWhenStopped);

    connect(step_animation,SIGNAL(finished()),this,SLOT(arrived()));
    position = block_num;
}

void Player::stepForward(){
    position = NEXT_POS(position);
    if(position == 0){
        giveSalary();
    }
}

void Player::arrived(){
    qDebug() << "arrived at:"<<position;
    emit playerArrived(this);
}

bool Player::hasBlock(Block* block)
{
    // subject block check
    if(block->getType() != BlockType::SUBJECT) {
        qDebug() << "This is not a Subject Block!";
        return false;
    }

    list<Block*>::iterator finder = own_blocks.end();
    finder = find(own_blocks.begin(), own_blocks.end(), block);

    // no matching
    if(finder == own_blocks.end())
        return false;
    else
        return true;
}

void Player::addBlock(Block *block)
{
    SubjectBlock * subj_block = dynamic_cast<SubjectBlock*>(block);
    subj_block->setOwner(this);
    registered.find(((SubjectBlock*)block)->getDept())->second++;
    own_blocks.push_back(block);
}

void Player::removeBlock(Block *block)
{
    if(!hasBlock(block)) {
        qDebug() << "You don't have that block. Check Again!";
        return;
    }
    SubjectBlock * sblock = dynamic_cast<SubjectBlock*>(block);
    sblock->setGrade(SubjectBlock::NONE);
    registered.find(((SubjectBlock*)block)->getDept())->second--;
    own_blocks.remove(block);
}

void Player::giveSalary()
{
    qDebug() << "Player " << id << " received salary";
    //maybe add animation for gaining energy

    QMediaPlayer* mediaplayer = new QMediaPlayer();
    mediaplayer->setMedia(QUrl::fromLocalFile(QFileInfo("sound/coin.wav").absoluteFilePath()));
    mediaplayer->setVolume(100);
    mediaplayer->play();

    if(character_type == CharacterType::HARD_WORKER)
        energy += 150;
    else
        energy += 100;

    emit energyChanged(this->energy);
}

bool Player::checkWinStatus()
{
    int majored = 0;

    for(map<SubjectType::Type, int>::iterator i = registered.begin(); i != registered.end(); i++) {
        if(i->second == 3)
            majored ++;
    }

    if(plural && majored >= 2)
        return true;
    else if (!plural && majored >= 1)
        return true;
    else
        return false;
}

void Player::payEnergy(int payenergy)
{
    if(energy >= payenergy)
        energy-=payenergy;
    else{
        if(getAssetValue() >= payenergy){
            Sellpopup * popup = new Sellpopup;
            popup->show();
        }
        else
            setBankrupt();
    }
    emit energyChanged(this->energy);
}
void Player::giveEnergy(int paidenergy){
    energy+=paidenergy;
    emit energyChanged(this->energy);
}

int Player::getId() const {
    return id;
}

void Player::setType(CharacterType::Type type) {
    character_type = type;
}

int Player::getAssetValue() {

    int asset = 0;

    if(own_blocks.empty()) {
        qDebug() << "Player has nothing!";
        asset = 0;
    }
    else {
        for(list<Block*>::iterator itor = own_blocks.begin(); itor != own_blocks.end(); itor++) {
           asset += dynamic_cast<SubjectBlock*>(*itor)->getSellCost();
        }
    }
    return asset;
}

void Player::animatePlayerImage(int frame){
    QString filename = QString(":/images/ingame/character/");

    int zone = position /8 ;

    if(zone == 0){
        filename += QString("top_up_id_");
    }
    else if(zone ==1){
        filename += QString("top_right_id_");
    }
    else if(zone ==2){
        filename += QString("top_down_id_");
    }
    else {
        filename += QString("top_right_id_");
    }

    filename += player_color + QString("_");

    LocalGame * game_inst = LocalGame::getInst();

    if(game_inst->getGameState() == LocalGameState::PLAYER_MOVING
            && game_inst->getCurrentPlayer() == this)
        filename += QString("walk_");
    else
        filename += QString("stand_");

    filename += QString::number(frame).rightJustified(3,'0') + QString(".png");

    //qDebug() << filename;

    QImage image(filename);

    QTransform rotate;
    rotate.rotate(180);

    if(zone == 3)
        image = image.mirrored(true,false);

    setPixmap(QPixmap::fromImage(image));
}
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XEUS_EXPORT_HPP
#define XEUS_EXPORT_HPP

#ifdef _WIN32
    #ifdef XEUS_EXPORTS
        #define XEUS_API __declspec(dllexport)
    #else
        #define XEUS_API __declspec(dllimport)
    #endif
#else
    #define XEUS_API
#endif

#define XEUS_VERSION_MAJOR 0
#define XEUS_VERSION_MINOR 8
#define XEUS_VERSION_PATCH 0

#endif
<commit_msg>Release 0.8.1<commit_after>/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XEUS_EXPORT_HPP
#define XEUS_EXPORT_HPP

#ifdef _WIN32
    #ifdef XEUS_EXPORTS
        #define XEUS_API __declspec(dllexport)
    #else
        #define XEUS_API __declspec(dllimport)
    #endif
#else
    #define XEUS_API
#endif

#define XEUS_VERSION_MAJOR 0
#define XEUS_VERSION_MINOR 8
#define XEUS_VERSION_PATCH 1

#endif
<|endoftext|>


<commit_before>#include "clientmanager.h"

/**
 * Check to see if a window is a registered client window.
 * @param window The window to check.
 * @return Whether or not the window represents a client.
 */
bool ClientManager::is_client(Window window)
{
    return m_clients.count(window) > 0;
}

/**
 * Gets the icon structure which is owns the given window.
 * @param window The window to find.
 * @return Either hte owning Icon, or NULL.
 */
Icon *ClientManager::get_icon(Window window)
{
    for (std::map<Window,Icon*>::iterator icon_iter = m_icons.begin();
            icon_iter != m_icons.end();
            icon_iter++)
    {
        if (icon_iter->second->window == window)
            return icon_iter->second;
    }

    return NULL;
}

/**
 * Gets the state of a particular client.
 * @param window The window of the client.
 * @return The state of the client which owns the window.
 */
ClientState ClientManager::get_state(Window window)
{
    return m_clients[window];
}

/**
 * Handle a motion event, which updates the client which is currently being
 * moved or resized.
 * @param event The X MotionNotify event.
 */
void ClientManager::handle_motion(const XEvent &event)
{
    if (m_mvr.client == None)
        return;

    ClientState state = m_clients[m_mvr.client];

    // Get the most recent event, to skip needless updates
    XEvent latest = event;
    while (XCheckTypedEvent(m_shared.display, MotionNotify, &latest));

    // Find out the pointer delta, relative to where it was previously
    Dimension xdiff = latest.xbutton.x_root - DIM2D_X(m_mvr.ptr_loc),
              ydiff = latest.xbutton.y_root - DIM2D_Y(m_mvr.ptr_loc);

    m_mvr.ptr_loc = Dimension2D(latest.xbutton.x_root, latest.xbutton.y_root);

    // Find out where the placeholder is now; the xdiff and ydiff are used
    // relative to this
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, m_mvr.window, &attr);

    switch (state)
    {
        case CS_MOVING:
            XMoveWindow(m_shared.display, m_mvr.window,
                    attr.x + xdiff, attr.y + ydiff);
            break;
        case CS_RESIZING:
        {
            Dimension width = std::max<Dimension>(attr.width + xdiff, 1),
                      height = std::max<Dimension>(attr.height + ydiff, 1);
            XResizeWindow(m_shared.display, m_mvr.window, width, height);
        }; break;
    }
}

/**
 * Transitions from one state to another, given a client window.
 * @param window The client to transition.
 * @param new_state The new state to attempt to transition to.
 */
void ClientManager::state_transition(Window window, ClientState new_state)
{
    if (!is_client(window))
        return;

    // Save the current window's attributes, should any transition need them
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, window, &attr);

    ClientState old_state = m_clients[window];

    if (old_state == CS_ACTIVE)
    {
        if (new_state == CS_ICON)
        {
            unfocus(window);
            unmap(window);
            make_icon(window);
        }
        if (new_state == CS_VISIBLE)
        {
            unfocus(window);
            m_clients[window] = CS_VISIBLE;
        }
        if (new_state == CS_INVISIBLE)
        {
            unfocus(window);
            unmap(window);
            m_clients[window] = CS_INVISIBLE;
        }
        if (new_state == CS_MOVING)
        {
            unfocus(window);
            unmap(window);
            begin_moving(window, attr);
        }
        if (new_state == CS_RESIZING)
        {
            unfocus(window);
            unmap(window);
            begin_resizing(window, attr);
        }
        if (new_state == CS_DESTROY)
        {
            destroy(window);
        }
    }

    if (old_state == CS_VISIBLE)
    {
        if (new_state == CS_ACTIVE)
        {
            focus(window);
        }
        if (new_state == CS_INVISIBLE)
        {
            unmap(window);
            m_clients[window] = CS_INVISIBLE;
        }
        if (new_state == CS_DESTROY)
        {
            destroy(window);
        }
    }

    if (old_state == CS_INVISIBLE)
    {
        if (new_state == CS_VISIBLE)
        {
            map(window);
            m_clients[window] = CS_VISIBLE;
        }
        if (new_state == CS_DESTROY)
        {
            destroy(window);
        }
    }

    if (old_state == CS_ICON)
    {
        Icon *icon = get_icon(window);

        if (new_state == CS_ACTIVE)
        {
            delete_icon(icon->window);
            map(window);
            focus(window);
        }
        if (new_state == CS_DESTROY)
        {
            delete_icon(icon->window);
            destroy(window);
        }
    }

    if (old_state == CS_MOVING)
    {
        if (new_state == CS_ACTIVE)
        {
            map(window);
            end_move_resize();
            focus(window);
        }
        if (new_state == CS_DESTROY)
        {
            end_move_resize_unsafe();
            destroy(window);
        }
    }

    if (old_state == CS_RESIZING)
    {
        if (new_state == CS_ACTIVE)
        {
            map(window);
            end_move_resize();
            focus(window);
        }
        if (new_state == CS_DESTROY)
        {
            end_move_resize_unsafe();
            destroy(window);
        }
    }
}

/**
 * Creates a new client.
 * @param window The window of the new client to create.
 */
void ClientManager::create(Window window)
{
    // Ignore any non-managable windows
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, window, &attr);

    if (attr.override_redirect)
        return;

    // Transient is the ICCCM term for a window which is a dialog of
    // another client.
    bool is_transient = false;

    Window transient_for;
    if (XGetTransientForHint(m_shared.display, window, &transient_for) &&
            transient_for != None)
        is_transient = true;

    XSetWindowBorder(m_shared.display, window,
            WhitePixel(m_shared.display, m_shared.screen));
    XSetWindowBorderWidth(m_shared.display, window, m_shared.border_width);

    focus(window);
}

/**
 * Removes a now non-existant client from the registry.
 * @param window The now non-existant window to delete.
 */
void ClientManager::destroy(Window window)
{
    m_layers.erase(window);
    m_desktops.erase(window);
    m_sticky.erase(window);
    m_clients.erase(window);
}

/**
 * Requests that a client close, without actually closing it directly.
 * @param window The client window to close.
 */
void ClientManager::close(Window window)
{
    XEvent close_event;
    XClientMessageEvent client_close = {
        .type = ClientMessage,
        .window = window,
        .message_type = XInternAtom(m_shared.display, "WM_PROTOCOLS", false),
        .format = 32,
        .data = {
            .l = static_cast<long>
                (XInternAtom(m_shared.display, "WM_DELETE_WINDOW", false),CurrentTime)
        }
    };

    close_event.xclient = client_close;
    XSendEvent(m_shared.display, window, False, NoEventMask, &close_event);
}

/**
 * Set the focus on a particular window, unfocusing the previous window.
 * @param window The client window to focus on.
 */
void ClientManager::focus(Window window)
{
    // Find the currently focused window
    for (std::map<Window,ClientState>::iterator client_iter = m_clients.begin();
            client_iter != m_clients.end();
            client_iter++)
    {
        if (client_iter->second == CS_ACTIVE)
        {
            // Make sure to unfocus this client before moving on
            state_transition(window, CS_VISIBLE);
            break;
        }
    }

    // It is guaranteed that no window is focused now - make sure this window can
    // accept focus before transferring the focus over
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, window, &attr);

    if (attr.c_class != InputOnly && attr.map_state == IsViewable)
    {
        XUngrabButton(m_shared.display, AnyButton, AnyModifier, window);
        XSetInputFocus(m_shared.display, window, RevertToPointerRoot, CurrentTime);

        Window new_focus;
        int _unused;
        XGetInputFocus(m_shared.display, &new_focus, &_unused);

        // If this window isn't actually focused, then re-execute the grab
        if (new_focus != window)
        {
            unfocus(window);
            m_clients[window] = CS_VISIBLE;
        }
        else
        {
            m_clients[window] = CS_ACTIVE;
        }
    }
}

/**
 * Causes the client to lose its input focus.
 * @param window The client window to unfocus.
 */
void ClientManager::unfocus(Window window)
{
    XGrabButton(m_shared.display, AnyButton, AnyModifier, window, false,
            ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
            None, None);
}

/**
 * Maps a window onto the screen, making it visible.
 * @param window The client window to show.
 */
void ClientManager::map(Window window)
{
    XMapWindow(m_shared.display, window);
}

/**
 * Unmaps a window off the screen.
 * @param window The client window to hide.
 */
void ClientManager::unmap(Window window)
{
    XUnmapWindow(m_shared.display, window);
}
<commit_msg>ClientManager::create now initializes layer and desktop data for clients.<commit_after>#include "clientmanager.h"

/**
 * Check to see if a window is a registered client window.
 * @param window The window to check.
 * @return Whether or not the window represents a client.
 */
bool ClientManager::is_client(Window window)
{
    return m_clients.count(window) > 0;
}

/**
 * Gets the icon structure which is owns the given window.
 * @param window The window to find.
 * @return Either hte owning Icon, or NULL.
 */
Icon *ClientManager::get_icon(Window window)
{
    for (std::map<Window,Icon*>::iterator icon_iter = m_icons.begin();
            icon_iter != m_icons.end();
            icon_iter++)
    {
        if (icon_iter->second->window == window)
            return icon_iter->second;
    }

    return NULL;
}

/**
 * Gets the state of a particular client.
 * @param window The window of the client.
 * @return The state of the client which owns the window.
 */
ClientState ClientManager::get_state(Window window)
{
    return m_clients[window];
}

/**
 * Handle a motion event, which updates the client which is currently being
 * moved or resized.
 * @param event The X MotionNotify event.
 */
void ClientManager::handle_motion(const XEvent &event)
{
    if (m_mvr.client == None)
        return;

    ClientState state = m_clients[m_mvr.client];

    // Get the most recent event, to skip needless updates
    XEvent latest = event;
    while (XCheckTypedEvent(m_shared.display, MotionNotify, &latest));

    // Find out the pointer delta, relative to where it was previously
    Dimension xdiff = latest.xbutton.x_root - DIM2D_X(m_mvr.ptr_loc),
              ydiff = latest.xbutton.y_root - DIM2D_Y(m_mvr.ptr_loc);

    m_mvr.ptr_loc = Dimension2D(latest.xbutton.x_root, latest.xbutton.y_root);

    // Find out where the placeholder is now; the xdiff and ydiff are used
    // relative to this
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, m_mvr.window, &attr);

    switch (state)
    {
        case CS_MOVING:
            XMoveWindow(m_shared.display, m_mvr.window,
                    attr.x + xdiff, attr.y + ydiff);
            break;
        case CS_RESIZING:
        {
            Dimension width = std::max<Dimension>(attr.width + xdiff, 1),
                      height = std::max<Dimension>(attr.height + ydiff, 1);
            XResizeWindow(m_shared.display, m_mvr.window, width, height);
        }; break;
    }
}

/**
 * Transitions from one state to another, given a client window.
 * @param window The client to transition (or, possibly an icon window)
 * @param new_state The new state to attempt to transition to.
 */
void ClientManager::state_transition(Window window, ClientState new_state)
{
    if (!is_client(window))
        return;

    // Save the current window's attributes, should any transition need them
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, window, &attr);

    ClientState old_state = m_clients[window];

    if (old_state == CS_ACTIVE)
    {
        if (new_state == CS_ICON)
        {
            unfocus(window);
            unmap(window);
            make_icon(window);
        }
        if (new_state == CS_VISIBLE)
        {
            unfocus(window);
            m_clients[window] = CS_VISIBLE;
        }
        if (new_state == CS_INVISIBLE)
        {
            unfocus(window);
            unmap(window);
            m_clients[window] = CS_INVISIBLE;
        }
        if (new_state == CS_MOVING)
        {
            unfocus(window);
            unmap(window);
            begin_moving(window, attr);
        }
        if (new_state == CS_RESIZING)
        {
            unfocus(window);
            unmap(window);
            begin_resizing(window, attr);
        }
        if (new_state == CS_DESTROY)
        {
            destroy(window);
        }
    }

    if (old_state == CS_VISIBLE)
    {
        if (new_state == CS_ACTIVE)
        {
            focus(window);
        }
        if (new_state == CS_INVISIBLE)
        {
            unmap(window);
            m_clients[window] = CS_INVISIBLE;
        }
        if (new_state == CS_DESTROY)
        {
            destroy(window);
        }
    }

    if (old_state == CS_INVISIBLE)
    {
        if (new_state == CS_VISIBLE)
        {
            map(window);
            m_clients[window] = CS_VISIBLE;
        }
        if (new_state == CS_DESTROY)
        {
            destroy(window);
        }
    }

    if (old_state == CS_ICON)
    {
        Icon *icon = get_icon(window);

        if (new_state == CS_ACTIVE)
        {
            delete_icon(icon->window);
            map(window);
            focus(window);
        }
        if (new_state == CS_DESTROY)
        {
            delete_icon(icon->window);
            destroy(window);
        }
    }

    if (old_state == CS_MOVING)
    {
        if (new_state == CS_ACTIVE)
        {
            map(window);
            end_move_resize();
            focus(window);
        }
        if (new_state == CS_DESTROY)
        {
            end_move_resize_unsafe();
            destroy(window);
        }
    }

    if (old_state == CS_RESIZING)
    {
        if (new_state == CS_ACTIVE)
        {
            map(window);
            end_move_resize();
            focus(window);
        }
        if (new_state == CS_DESTROY)
        {
            end_move_resize_unsafe();
            destroy(window);
        }
    }
}

/**
 * Creates a new client.
 * @param window The window of the new client to create.
 */
void ClientManager::create(Window window)
{
    // Ignore any non-managable windows
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, window, &attr);

    if (attr.override_redirect)
        return;

    // Transient is the ICCCM term for a window which is a dialog of
    // another client.
    bool is_transient = false;

    Window transient_for;
    if (XGetTransientForHint(m_shared.display, window, &transient_for) &&
            transient_for != None)
        is_transient = true;

    XSetWindowBorder(m_shared.display, window,
            WhitePixel(m_shared.display, m_shared.screen));
    XSetWindowBorderWidth(m_shared.display, window, m_shared.border_width);

    focus(window);
    m_layers[window] = is_transient ? 5 : DIALOG_LAYER;
    m_sticky[window] = false;
    m_desktops[window] = m_current_desktop;

    relayer();
    update_desktop();
}

/**
 * Removes a now non-existant client from the registry.
 * @param window The now non-existant window to delete.
 */
void ClientManager::destroy(Window window)
{
    m_layers.erase(window);
    m_desktops.erase(window);
    m_sticky.erase(window);
    m_clients.erase(window);
}

/**
 * Requests that a client close, without actually closing it directly.
 * @param window The client window to close.
 */
void ClientManager::close(Window window)
{
    XEvent close_event;
    XClientMessageEvent client_close = {
        .type = ClientMessage,
        .window = window,
        .message_type = XInternAtom(m_shared.display, "WM_PROTOCOLS", false),
        .format = 32,
        .data = {
            .l = static_cast<long>
                (XInternAtom(m_shared.display, "WM_DELETE_WINDOW", false),CurrentTime)
        }
    };

    close_event.xclient = client_close;
    XSendEvent(m_shared.display, window, False, NoEventMask, &close_event);
}

/**
 * Set the focus on a particular window, unfocusing the previous window.
 * @param window The client window to focus on.
 */
void ClientManager::focus(Window window)
{
    // Find the currently focused window
    for (std::map<Window,ClientState>::iterator client_iter = m_clients.begin();
            client_iter != m_clients.end();
            client_iter++)
    {
        if (client_iter->second == CS_ACTIVE)
        {
            // Make sure to unfocus this client before moving on
            state_transition(window, CS_VISIBLE);
            break;
        }
    }

    // It is guaranteed that no window is focused now - make sure this window can
    // accept focus before transferring the focus over
    XWindowAttributes attr;
    XGetWindowAttributes(m_shared.display, window, &attr);

    if (attr.c_class != InputOnly && attr.map_state == IsViewable)
    {
        XUngrabButton(m_shared.display, AnyButton, AnyModifier, window);
        XSetInputFocus(m_shared.display, window, RevertToPointerRoot, CurrentTime);

        Window new_focus;
        int _unused;
        XGetInputFocus(m_shared.display, &new_focus, &_unused);

        // If this window isn't actually focused, then re-execute the grab
        if (new_focus != window)
        {
            unfocus(window);
            m_clients[window] = CS_VISIBLE;
        }
        else
        {
            m_clients[window] = CS_ACTIVE;
        }
    }
}

/**
 * Causes the client to lose its input focus.
 * @param window The client window to unfocus.
 */
void ClientManager::unfocus(Window window)
{
    XGrabButton(m_shared.display, AnyButton, AnyModifier, window, false,
            ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
            None, None);
}

/**
 * Maps a window onto the screen, making it visible.
 * @param window The client window to show.
 */
void ClientManager::map(Window window)
{
    XMapWindow(m_shared.display, window);
}

/**
 * Unmaps a window off the screen.
 * @param window The client window to hide.
 */
void ClientManager::unmap(Window window)
{
    XUnmapWindow(m_shared.display, window);
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
//
// This file is part of Qt Creator Boost.Build plugin project.
//
// This is free software; you can redistribute and/or modify it under
// the terms of the GNU Lesser General Public License, Version 2.1
// as published by the Free Software Foundation.
// See accompanying file LICENSE.txt or copy at
// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
//
#ifndef BBUTILITY_HPP
#define BBUTILITY_HPP
#ifdef _DEBUG

#include "bbprojectmanagerconstants.hpp"
// Qt
#include <QDebug>
#include <QHash>
#include <QSet>
#include <QString>
#include <QStringList>

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

#define BBPM_QDEBUG(msg) \
    qDebug() \
        << "[" << BoostBuildProjectManager::Constants::BOOSTBUILD << "] " \
        << "(" << __PRETTY_FUNCTION__ << ")"; \
    qDebug().nospace() << "\t" << msg

#else
nospace
#define BBPM_QDEBUG(msg)

#endif // _DEBUG

#define BBPM_C(CONSTANT) QLatin1String(BoostBuildProjectManager::Constants::CONSTANT)

//////////////////////////////////////////////////////////////////////////////////////////
namespace BoostBuildProjectManager {
namespace Utility {

// Read all lines from a file.
QStringList readLines(QString const& absoluteFileName);

// Converts the path from relative to the project to an absolute path.
QStringList makeAbsolutePaths(QString const& basePath, QStringList const& paths);

QStringList& makeRelativePaths(QString const& basePath, QStringList& paths);

QHash<QString, QStringList> sortFilesIntoPaths(QString const& basePath
                                             , QSet<QString> const& files);

QString parseJamfileProjectName(QString const& fileName);

} // namespace Utility
} // namespace BoostBuildProjectManager

#endif // BBUTILITY_HPP
<commit_msg>Fix non-debug builds<commit_after>//
// Copyright (C) 2013 Mateusz Łoskot <mateusz@loskot.net>
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
//
// This file is part of Qt Creator Boost.Build plugin project.
//
// This is free software; you can redistribute and/or modify it under
// the terms of the GNU Lesser General Public License, Version 2.1
// as published by the Free Software Foundation.
// See accompanying file LICENSE.txt or copy at
// http://www.gnu.org/licenses/lgpl-2.1-standalone.html.
//
#ifndef BBUTILITY_HPP
#define BBUTILITY_HPP

#include "bbprojectmanagerconstants.hpp"
// Qt
#include <QDebug>
#include <QHash>
#include <QSet>
#include <QString>
#include <QStringList>

//////////////////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG

#define BBPM_QDEBUG(msg) \
    qDebug() \
        << "[" << BoostBuildProjectManager::Constants::BOOSTBUILD << "] " \
        << "(" << __PRETTY_FUNCTION__ << ")"; \
    qDebug().nospace() << "\t" << msg

#else
#define BBPM_QDEBUG(msg)

#endif // _DEBUG

#define BBPM_C(CONSTANT) QLatin1String(BoostBuildProjectManager::Constants::CONSTANT)

//////////////////////////////////////////////////////////////////////////////////////////
namespace BoostBuildProjectManager {
namespace Utility {

// Read all lines from a file.
QStringList readLines(QString const& absoluteFileName);

// Converts the path from relative to the project to an absolute path.
QStringList makeAbsolutePaths(QString const& basePath, QStringList const& paths);

QStringList& makeRelativePaths(QString const& basePath, QStringList& paths);

QHash<QString, QStringList> sortFilesIntoPaths(QString const& basePath
                                             , QSet<QString> const& files);

QString parseJamfileProjectName(QString const& fileName);

} // namespace Utility
} // namespace BoostBuildProjectManager

#endif // BBUTILITY_HPP
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/thread/FixedSizeThreadPool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-logtable/LogTableServlet.h"
#include "fnord-logtable/TableRepository.h"
#include "fnord-logtable/TableJanitor.h"
#include "fnord-logtable/TableReplication.h"
#include "fnord-afx/ArtifactReplication.h"
#include "fnord-afx/ArtifactIndexReplication.h"
#include "fnord-logtable/NumericBoundsSummary.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-msg/MessageSchema.h"
#include "fnord-tsdb/TSDBNode.h"
#include "fnord-tsdb/TSDBServlet.h"
#include "common.h"
#include "schemas.h"
#include "ModelReplication.h"
#include "JoinedSessionViewer.h"

using namespace fnord;

std::atomic<bool> shutdown_sig;
fnord::thread::EventLoop ev;

void quit(int n) {
  shutdown_sig = true;
  fnord::logInfo("cm.chunkserver", "Shutting down...");
  // FIXPAUL: wait for http server stop...
  ev.shutdown();
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  shutdown_sig = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "datadir path",
      "<path>");

  flags.defineFlag(
      "replicate_to",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "url",
      "<url>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* args */
  auto dir = flags.getString("datadir");
  auto repl_targets = flags.getStrings("replicate_to");

  /* load schemas */
  msg::MessageSchemaRepository schemas;
  loadDefaultSchemas(&schemas);

  /* start http server and worker pools */
  fnord::thread::ThreadPool tpool;
  http::HTTPConnectionPool http(&ev);
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  JoinedSessionViewer jsessviewer;
  http_router.addRouteByPrefixMatch("/sessviewer", &jsessviewer);

  auto repl_scheme = mkRef(new dht::FixedReplicationScheme());
  for (const auto& r : repl_targets) {
    repl_scheme->addHost(r);
  }

  tsdb::TSDBNode tsdb_node(dir + "/tsdb", repl_scheme.get(), &http);

  {
    tsdb::StreamConfig config;
    config.max_datafile_size = 1024 * 1024 * 512;
    config.chunk_size = Duration(3600 * 4 * kMicrosPerSecond);
    config.compaction_interval = Duration(1800 * kMicrosPerSecond);
    tsdb_node.configurePrefix("joined_sessions.", config);
  }

  tsdb::TSDBServlet tsdb_servlet(&tsdb_node);
  http_router.addRouteByPrefixMatch("/tsdb", &tsdb_servlet, &tpool);

  tsdb_node.start();
  ev.run();

  tsdb_node.stop();
  fnord::logInfo("cm.chunkserver", "Exiting...");

  exit(0);
}

<commit_msg>StreamConfig...<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/thread/FixedSizeThreadPool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-logtable/LogTableServlet.h"
#include "fnord-logtable/TableRepository.h"
#include "fnord-logtable/TableJanitor.h"
#include "fnord-logtable/TableReplication.h"
#include "fnord-afx/ArtifactReplication.h"
#include "fnord-afx/ArtifactIndexReplication.h"
#include "fnord-logtable/NumericBoundsSummary.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-msg/MessageSchema.h"
#include "fnord-tsdb/TSDBNode.h"
#include "fnord-tsdb/TSDBServlet.h"
#include "common.h"
#include "schemas.h"
#include "ModelReplication.h"
#include "JoinedSessionViewer.h"

using namespace fnord;

std::atomic<bool> shutdown_sig;
fnord::thread::EventLoop ev;

void quit(int n) {
  shutdown_sig = true;
  fnord::logInfo("cm.chunkserver", "Shutting down...");
  // FIXPAUL: wait for http server stop...
  ev.shutdown();
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  shutdown_sig = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "datadir path",
      "<path>");

  flags.defineFlag(
      "replicate_to",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "url",
      "<url>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* args */
  auto dir = flags.getString("datadir");
  auto repl_targets = flags.getStrings("replicate_to");

  /* load schemas */
  msg::MessageSchemaRepository schemas;
  loadDefaultSchemas(&schemas);

  /* start http server and worker pools */
  fnord::thread::ThreadPool tpool;
  http::HTTPConnectionPool http(&ev);
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  JoinedSessionViewer jsessviewer;
  http_router.addRouteByPrefixMatch("/sessviewer", &jsessviewer);

  auto repl_scheme = mkRef(new dht::FixedReplicationScheme());
  for (const auto& r : repl_targets) {
    repl_scheme->addHost(r);
  }

  tsdb::TSDBNode tsdb_node(dir + "/tsdb", repl_scheme.get(), &http);

  {
    tsdb::StreamConfig config;
    config.set_stream_key_prefix("joined_sessions.");
    config.set_max_sstable_size(1024 * 1024 * 512);
    config.set_compaction_interval(1800 * kMicrosPerSecond);
    config.set_partitioner(tsdb::TIME_WINDOW);
    config.set_partition_window(3600 * 4 * kMicrosPerSecond);
    tsdb_node.configurePrefix(config);
  }

  tsdb::TSDBServlet tsdb_servlet(&tsdb_node);
  http_router.addRouteByPrefixMatch("/tsdb", &tsdb_servlet, &tpool);

  tsdb_node.start();
  ev.run();

  tsdb_node.stop();
  fnord::logInfo("cm.chunkserver", "Exiting...");

  exit(0);
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-base/InternMap.h"
#include "fnord-json/json.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-sstable/sstablewriter.h"
#include "fnord-sstable/SSTableColumnSchema.h"
#include "fnord-sstable/SSTableColumnReader.h"
#include "fnord-sstable/SSTableColumnWriter.h"
#include "fnord-cstable/UInt16ColumnReader.h"
#include "fnord-cstable/UInt16ColumnWriter.h"
#include "fnord-cstable/CSTableWriter.h"
#include "fnord-cstable/CSTableReader.h"
#include "common.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "CTRCounter.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  cstable::UInt16ColumnWriter position_col;

  uint64_t r = 0;
  uint64_t n = 0;

  auto add_session = [&] (const cm::JoinedSession& sess) {
    ++n;
    for (const auto& q : sess.queries) {
      for (const auto& i : q.items) {
        position_col.addDatum(r, 0, i.position);
        r = 2;
      }

      r = 1;
    }

    r = 0;
  };

  /* read input tables */
  auto sstables = flags.getArgv();
  int row_idx = 0;
  for (int tbl_idx = 0; tbl_idx < sstables.size(); ++tbl_idx) {
    const auto& sstable = sstables[tbl_idx];
    fnord::logInfo("cm.jqcolumnize", "Importing sstable: $0", sstable);

    /* read sstable header */
    sstable::SSTableReader reader(File::openFile(sstable, File::O_READ));

    if (reader.bodySize() == 0) {
      fnord::logCritical("cm.jqcolumnize", "unfinished sstable: $0", sstable);
      exit(1);
    }

    /* get sstable cursor */
    auto cursor = reader.getCursor();
    auto body_size = reader.bodySize();

    /* status line */
    util::SimpleRateLimitedFn status_line(kMicrosPerSecond, [&] () {
      fnord::logInfo(
          "cm.jqcolumnize",
          "[$1/$2] [$0%] Reading sstable... rows=$3",
          (size_t) ((cursor->position() / (double) body_size) * 100),
          tbl_idx + 1, sstables.size(), row_idx);
    });

    /* read sstable rows */
    for (; cursor->valid(); ++row_idx) {
      status_line.runMaybe();

      auto key = cursor->getKeyString();
      auto val = cursor->getDataBuffer();
      Option<cm::JoinedQuery> q;

      try {
        q = Some(json::fromJSON<cm::JoinedQuery>(val));
      } catch (const Exception& e) {
        fnord::logWarning("cm.jqcolumnize", e, "invalid json: $0", val.toString());
      }

      if (!q.isEmpty()) {
        cm::JoinedSession s;
        s.queries.emplace_back(q.get());
        add_session(s);
      }

      if (!cursor->next()) {
        break;
      }
    }

    status_line.runForce();
  }

  if (sstables.size() > 0) {
    cstable::CSTableWriter writer("fnord.cstable", n);
    writer.addColumn("queries.items.position", &position_col);
    writer.commit();
  }

  auto t0 = WallClock::unixMicros();
  cstable::CSTableReader reader("fnord.cstable");
  void* coldata;
  size_t colsize;
  reader.getColumn("queries.items.position", &coldata, &colsize);
  cstable::UInt16ColumnReader poscol_reader(coldata, colsize);

  auto t1 = WallClock::unixMicros();
  HashMap<uint16_t, Pair<uint64_t, uint64_t>> posi_info;

  uint64_t d;
  uint16_t val;
  while (poscol_reader.next(&r, &d, &val)) {
    ++posi_info[val].first;
    //fnord::iputs("val: $0", val);
  }

  auto t2 = WallClock::unixMicros();
  fnord::iputs("reading took $0ms ($1ms)", (t2 - t0) / 1000.0f, (t2 - t1) / 1000.0f);

  return 0;
}

<commit_msg>build ctr by posi stats<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-base/InternMap.h"
#include "fnord-json/json.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-sstable/sstablewriter.h"
#include "fnord-sstable/SSTableColumnSchema.h"
#include "fnord-sstable/SSTableColumnReader.h"
#include "fnord-sstable/SSTableColumnWriter.h"
#include "fnord-cstable/UInt16ColumnReader.h"
#include "fnord-cstable/UInt16ColumnWriter.h"
#include "fnord-cstable/CSTableWriter.h"
#include "fnord-cstable/CSTableReader.h"
#include "common.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "CTRCounter.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  cstable::UInt16ColumnWriter position_col;
  cstable::UInt16ColumnWriter clicked_col;

  uint64_t r = 0;
  uint64_t n = 0;

  auto add_session = [&] (const cm::JoinedSession& sess) {
    ++n;
    for (const auto& q : sess.queries) {
      for (const auto& i : q.items) {
        position_col.addDatum(r, 0, i.position);
        clicked_col.addDatum(r, 0, i.clicked);
        r = 2;
      }

      r = 1;
    }

    r = 0;
  };

  /* read input tables */
  auto sstables = flags.getArgv();
  int row_idx = 0;
  for (int tbl_idx = 0; tbl_idx < sstables.size(); ++tbl_idx) {
    const auto& sstable = sstables[tbl_idx];
    fnord::logInfo("cm.jqcolumnize", "Importing sstable: $0", sstable);

    /* read sstable header */
    sstable::SSTableReader reader(File::openFile(sstable, File::O_READ));

    if (reader.bodySize() == 0) {
      fnord::logCritical("cm.jqcolumnize", "unfinished sstable: $0", sstable);
      exit(1);
    }

    /* get sstable cursor */
    auto cursor = reader.getCursor();
    auto body_size = reader.bodySize();

    /* status line */
    util::SimpleRateLimitedFn status_line(kMicrosPerSecond, [&] () {
      fnord::logInfo(
          "cm.jqcolumnize",
          "[$1/$2] [$0%] Reading sstable... rows=$3",
          (size_t) ((cursor->position() / (double) body_size) * 100),
          tbl_idx + 1, sstables.size(), row_idx);
    });

    /* read sstable rows */
    for (; cursor->valid(); ++row_idx) {
      status_line.runMaybe();

      auto key = cursor->getKeyString();
      auto val = cursor->getDataBuffer();
      Option<cm::JoinedQuery> q;

      try {
        q = Some(json::fromJSON<cm::JoinedQuery>(val));
      } catch (const Exception& e) {
        fnord::logWarning("cm.jqcolumnize", e, "invalid json: $0", val.toString());
      }

      if (!q.isEmpty()) {
        cm::JoinedSession s;
        s.queries.emplace_back(q.get());
        add_session(s);
      }

      if (!cursor->next()) {
        break;
      }
    }

    status_line.runForce();
  }

  if (sstables.size() > 0) {
    cstable::CSTableWriter writer("fnord.cstable", n);
    writer.addColumn("queries.items.position", &position_col);
    writer.addColumn("queries.items.clicked", &clicked_col);
    writer.commit();
  }

  auto t0 = WallClock::unixMicros();
  cstable::CSTableReader reader("fnord.cstable");
  void* poscoldata;
  size_t poscolsize;
  reader.getColumn("queries.items.position", &poscoldata, &poscolsize);
  cstable::UInt16ColumnReader poscol_reader(poscoldata, poscolsize);
  void* clickedcoldata;
  size_t clickedcolsize;
  reader.getColumn("queries.items.clicked", &clickedcoldata, &clickedcolsize);
  cstable::UInt16ColumnReader clickedcol_reader(clickedcoldata, clickedcolsize);

  auto t1 = WallClock::unixMicros();
  HashMap<uint16_t, Pair<uint64_t, uint64_t>> posi_info;

  uint64_t d;
  uint16_t pos;
  uint16_t clicked;

  n = 0;
  while (poscol_reader.next(&r, &d, &pos) && clickedcol_reader.next(&r, &d, &clicked)) {
    ++posi_info[pos].first;
    posi_info[pos].second += clicked;
    ++n;
  }

  auto t2 = WallClock::unixMicros();
  fnord::iputs("reading $2 rows took $0ms ($1ms)", (t2 - t0) / 1000.0f, (t2 - t1) / 1000.0f, n);

  for (const auto& p : posi_info) {
    fnord::iputs("pos: $0, views: $1, clicks: $2, ctr: $3", p.first, p.second.first, p.second.second, p.second.second / (double) p.second.first);
  }

  return 0;
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-base/InternMap.h"
#include "fnord-json/json.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-sstable/sstablewriter.h"
#include "fnord-sstable/SSTableColumnSchema.h"
#include "fnord-sstable/SSTableColumnReader.h"
#include "fnord-sstable/SSTableColumnWriter.h"
#include "fnord-cstable/UInt32ColumnReader.h"
#include "fnord-cstable/UInt32ColumnWriter.h"
#include "fnord-cstable/BooleanColumnReader.h"
#include "fnord-cstable/BooleanColumnWriter.h"
#include "fnord-cstable/CSTableWriter.h"
#include "fnord-cstable/CSTableReader.h"
#include "common.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "CTRCounter.h"
#include "analytics/AnalyticsQuery.h"
#include "analytics/CTRByPositionQuery.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "input_file",
      fnord::cli::FlagParser::T_STRING,
      true,
      "i",
      NULL,
      "file",
      "<filename>");

  flags.defineFlag(
      "output_file",
      fnord::cli::FlagParser::T_STRING,
      true,
      "o",
      NULL,
      "file",
      "<filename>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  size_t debug_n = 0;
  size_t debug_z = 0;

  /* query level */
  cstable::UInt32ColumnWriter jq_page_col(1, 1, 100);
  cstable::UInt32ColumnWriter jq_lang_col(1, 1, kMaxLanguage);

  /* query item level */
  cstable::UInt32ColumnWriter jqi_position_col(2, 2, 64);
  cstable::BooleanColumnWriter jqi_clicked_col(2, 2);

  uint64_t r = 0;
  uint64_t n = 0;

  auto add_session = [&] (const cm::JoinedSession& sess) {
    ++n;

    for (const auto& q : sess.queries) {
      auto pg_str = cm::extractAttr(q.attrs, "pg");
      if (pg_str.isEmpty()) {
        jq_page_col.addNull(r, 1);
      } else {
        jq_page_col.addDatum(r, 1, std::stoul(pg_str.get()));
      }

      auto lang = cm::extractLanguage(q.attrs);
      uint32_t l = (uint16_t) lang;
      jq_lang_col.addDatum(r, 1, l);

      if (q.items.size() == 0) {
        jqi_position_col.addNull(r, 1);
        jqi_clicked_col.addNull(r, 1);
      }

      for (const auto& i : q.items) {
        jqi_position_col.addDatum(r, 2, i.position);
        jqi_clicked_col.addDatum(r, 2, i.clicked);
        r = 2;
      }

      r = 1;
    }

    r = 0;
  };

  /* read input tables */
  int row_idx = 0;

  const auto& sstable = flags.getString("input_file");
  fnord::logInfo("cm.jqcolumnize", "Importing sstable: $0", sstable);

  /* read sstable header */
  sstable::SSTableReader reader(File::openFile(sstable, File::O_READ));

  if (reader.bodySize() == 0) {
    fnord::logCritical("cm.jqcolumnize", "unfinished sstable: $0", sstable);
    exit(1);
  }

  /* get sstable cursor */
  auto cursor = reader.getCursor();
  auto body_size = reader.bodySize();

  /* status line */
  util::SimpleRateLimitedFn status_line(kMicrosPerSecond, [&] () {
    fnord::logInfo(
        "cm.jqcolumnize",
        "[$0%] Reading sstable... rows=$1",
        (size_t) ((cursor->position() / (double) body_size) * 100),
        row_idx);
  });

  /* read sstable rows */
  for (; cursor->valid(); ++row_idx) {
    status_line.runMaybe();

    auto key = cursor->getKeyString();
    auto val = cursor->getDataBuffer();
    Option<cm::JoinedQuery> q;

    try {
      q = Some(json::fromJSON<cm::JoinedQuery>(val));
    } catch (const Exception& e) {
      fnord::logWarning("cm.jqcolumnize", e, "invalid json: $0", val.toString());
    }

    if (!q.isEmpty()) {
      cm::JoinedSession s;
      s.queries.emplace_back(q.get());
      add_session(s);
    }

    if (!cursor->next()) {
      break;
    }
  }

  status_line.runForce();

  cstable::CSTableWriter writer(flags.getString("output_file"), n);
  writer.addColumn("queries.page", &jq_page_col);
  writer.addColumn("queries.language", &jq_lang_col);
  writer.addColumn("queries.items.position", &jqi_position_col);
  writer.addColumn("queries.items.clicked", &jqi_clicked_col);
  writer.commit();

  {
    cstable::CSTableReader reader(flags.getString("output_file"));
    auto t0 = WallClock::unixMicros();

    cm::AnalyticsQuery aq;
    cm::CTRByPositionQueryResult res;
    cm::CTRByPositionQuery q(&aq, &res);
    aq.scanTable(&reader);
    auto t1 = WallClock::unixMicros();
    fnord::iputs("scanned $0 rows in $1 ms", res.rows_scanned, (t1 - t0) / 1000.0f);
    for (const auto& p : res.counters) {
      fnord::iputs(
         "pos: $0, views: $1, clicks: $2, ctr: $3",
          p.first, p.second.num_views,
          p.second.num_clicks,
          p.second.num_clicks / (double) p.second.num_views);
    }
  }

  return 0;
}

<commit_msg>commit CSTable write atomically<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-base/InternMap.h"
#include "fnord-json/json.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-sstable/sstablewriter.h"
#include "fnord-sstable/SSTableColumnSchema.h"
#include "fnord-sstable/SSTableColumnReader.h"
#include "fnord-sstable/SSTableColumnWriter.h"
#include "fnord-cstable/UInt32ColumnReader.h"
#include "fnord-cstable/UInt32ColumnWriter.h"
#include "fnord-cstable/BooleanColumnReader.h"
#include "fnord-cstable/BooleanColumnWriter.h"
#include "fnord-cstable/CSTableWriter.h"
#include "fnord-cstable/CSTableReader.h"
#include "common.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "CTRCounter.h"
#include "analytics/AnalyticsQuery.h"
#include "analytics/CTRByPositionQuery.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "input_file",
      fnord::cli::FlagParser::T_STRING,
      true,
      "i",
      NULL,
      "file",
      "<filename>");

  flags.defineFlag(
      "output_file",
      fnord::cli::FlagParser::T_STRING,
      true,
      "o",
      NULL,
      "file",
      "<filename>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  size_t debug_n = 0;
  size_t debug_z = 0;

  /* query level */
  cstable::UInt32ColumnWriter jq_page_col(1, 1, 100);
  cstable::UInt32ColumnWriter jq_lang_col(1, 1, kMaxLanguage);

  /* query item level */
  cstable::UInt32ColumnWriter jqi_position_col(2, 2, 64);
  cstable::BooleanColumnWriter jqi_clicked_col(2, 2);

  uint64_t r = 0;
  uint64_t n = 0;

  auto add_session = [&] (const cm::JoinedSession& sess) {
    ++n;

    for (const auto& q : sess.queries) {
      auto pg_str = cm::extractAttr(q.attrs, "pg");
      if (pg_str.isEmpty()) {
        jq_page_col.addNull(r, 1);
      } else {
        jq_page_col.addDatum(r, 1, std::stoul(pg_str.get()));
      }

      auto lang = cm::extractLanguage(q.attrs);
      uint32_t l = (uint16_t) lang;
      jq_lang_col.addDatum(r, 1, l);

      if (q.items.size() == 0) {
        jqi_position_col.addNull(r, 1);
        jqi_clicked_col.addNull(r, 1);
      }

      for (const auto& i : q.items) {
        jqi_position_col.addDatum(r, 2, i.position);
        jqi_clicked_col.addDatum(r, 2, i.clicked);
        r = 2;
      }

      r = 1;
    }

    r = 0;
  };

  /* read input tables */
  int row_idx = 0;

  const auto& sstable = flags.getString("input_file");
  fnord::logInfo("cm.jqcolumnize", "Importing sstable: $0", sstable);

  /* read sstable header */
  sstable::SSTableReader reader(File::openFile(sstable, File::O_READ));

  if (reader.bodySize() == 0) {
    fnord::logCritical("cm.jqcolumnize", "unfinished sstable: $0", sstable);
    exit(1);
  }

  /* get sstable cursor */
  auto cursor = reader.getCursor();
  auto body_size = reader.bodySize();

  /* status line */
  util::SimpleRateLimitedFn status_line(kMicrosPerSecond, [&] () {
    fnord::logInfo(
        "cm.jqcolumnize",
        "[$0%] Reading sstable... rows=$1",
        (size_t) ((cursor->position() / (double) body_size) * 100),
        row_idx);
  });

  /* read sstable rows */
  for (; cursor->valid(); ++row_idx) {
    status_line.runMaybe();

    auto key = cursor->getKeyString();
    auto val = cursor->getDataBuffer();
    Option<cm::JoinedQuery> q;

    try {
      q = Some(json::fromJSON<cm::JoinedQuery>(val));
    } catch (const Exception& e) {
      fnord::logWarning("cm.jqcolumnize", e, "invalid json: $0", val.toString());
    }

    if (!q.isEmpty()) {
      cm::JoinedSession s;
      s.queries.emplace_back(q.get());
      add_session(s);
    }

    if (!cursor->next()) {
      break;
    }
  }

  status_line.runForce();

  {
    cstable::CSTableWriter writer(flags.getString("output_file") + "~", n);
    writer.addColumn("queries.page", &jq_page_col);
    writer.addColumn("queries.language", &jq_lang_col);
    writer.addColumn("queries.items.position", &jqi_position_col);
    writer.addColumn("queries.items.clicked", &jqi_clicked_col);
    writer.commit();
  }

  FileUtil::mv(
      flags.getString("output_file") + "~",
      flags.getString("output_file"));

  {
    cstable::CSTableReader reader(flags.getString("output_file"));
    auto t0 = WallClock::unixMicros();

    cm::AnalyticsQuery aq;
    cm::CTRByPositionQueryResult res;
    cm::CTRByPositionQuery q(&aq, &res);
    aq.scanTable(&reader);
    auto t1 = WallClock::unixMicros();
    fnord::iputs("scanned $0 rows in $1 ms", res.rows_scanned, (t1 - t0) / 1000.0f);
    for (const auto& p : res.counters) {
      fnord::iputs(
         "pos: $0, views: $1, clicks: $2, ctr: $3",
          p.first, p.second.num_views,
          p.second.num_clicks,
          p.second.num_clicks / (double) p.second.num_views);
    }
  }

  return 0;
}

<|endoftext|>