changeset 334:0b576ee64d45

* Create brand new hierarchy * Rename DynLib to Dynlib * Remove some warnings
author David Demelier <markand@malikania.fr>
date Sun, 08 Mar 2015 14:26:33 +0100
parents 412ca7a5e1ea
children 486767e1d165
files C++/Base64.cpp C++/Base64.h C++/Converter.cpp C++/Converter.h C++/Date.cpp C++/Date.h C++/Directory.cpp C++/Directory.h C++/Driver.cpp C++/Driver.h C++/DriverPostgres.cpp C++/DriverPostgres.h C++/DynLib.cpp C++/DynLib.h C++/Flags.h C++/Hash.cpp C++/Hash.h C++/Ini.cpp C++/Ini.h C++/Json.cpp C++/Json.h C++/OptionParser.cpp C++/OptionParser.h C++/Pack.cpp C++/Pack.h C++/Parser.cpp C++/Parser.h C++/Socket.cpp C++/Socket.h C++/SocketAddress.cpp C++/SocketAddress.h C++/SocketListener.cpp C++/SocketListener.h C++/SocketSsl.cpp C++/SocketSsl.h C++/SocketTcp.cpp C++/SocketTcp.h C++/SocketUdp.cpp C++/SocketUdp.h C++/Tests/Base64/CMakeLists.txt C++/Tests/Base64/main.cpp C++/Tests/Directory/CMakeLists.txt C++/Tests/Directory/main.cpp C++/Tests/DynLib/CMakeLists.txt C++/Tests/DynLib/Plugin.cpp C++/Tests/DynLib/main.cpp C++/Tests/Flags/CMakeLists.txt C++/Tests/Flags/main.cpp C++/Tests/Hash/CMakeLists.txt C++/Tests/Hash/main.cpp C++/Tests/Ini/CMakeLists.txt C++/Tests/Ini/configs/compact.conf C++/Tests/Ini/configs/error-badcomment.conf C++/Tests/Ini/configs/error-badsection.conf C++/Tests/Ini/configs/error-lineassigment.conf C++/Tests/Ini/configs/error-nosection.conf C++/Tests/Ini/configs/includes.conf C++/Tests/Ini/configs/multi.conf C++/Tests/Ini/configs/novalue.conf C++/Tests/Ini/configs/simple.conf C++/Tests/Ini/configs/tokens.conf C++/Tests/Ini/main.cpp C++/Tests/Json/CMakeLists.txt C++/Tests/Json/data/array-all.json C++/Tests/Json/data/array.json C++/Tests/Json/data/object-all.json C++/Tests/Json/data/object.json C++/Tests/Json/data/simple.json C++/Tests/Json/main.cpp C++/Tests/OptionParser/CMakeLists.txt C++/Tests/OptionParser/main.cpp C++/Tests/Pack/CMakeLists.txt C++/Tests/Pack/main.cpp C++/Tests/Parser/CMakeLists.txt C++/Tests/Parser/configs/multi.conf C++/Tests/Parser/configs/simple.conf C++/Tests/Parser/main.cpp C++/Tests/Sockets/CMakeLists.txt C++/Tests/Sockets/main.cpp C++/Tests/TreeNode/CMakeLists.txt C++/Tests/TreeNode/main.cpp C++/Tests/Utf8/CMakeLists.txt C++/Tests/Utf8/main.cpp C++/Tests/Xdg/CMakeLists.txt C++/Tests/Xdg/main.cpp C++/Tests/Zip/CMakeLists.txt C++/Tests/Zip/data/data.txt C++/Tests/Zip/data/stats.zip C++/Tests/Zip/main.cpp C++/TreeNode.h C++/Utf8.cpp C++/Utf8.h C++/Xdg.cpp C++/Xdg.h C++/ZipArchive.cpp C++/ZipArchive.h C++/doc/Dynlib/Home.md C++/doc/Dynlib/class/Dynlib.md C++/doc/Dynlib/class/Dynlib/Constructor.md C++/doc/Dynlib/class/Dynlib/Destructor.md C++/doc/Dynlib/class/Dynlib/Policy.md C++/doc/Dynlib/class/Dynlib/sym.md C++/doc/Dynlib/macro/DYNLIB_EXPORT.md C++/modules/Base64/Base64.cpp C++/modules/Base64/Base64.h C++/modules/Converter/Converter.cpp C++/modules/Converter/Converter.h C++/modules/Date/Date.cpp C++/modules/Date/Date.h C++/modules/Directory/Directory.cpp C++/modules/Directory/Directory.h C++/modules/Driver/Driver.cpp C++/modules/Driver/Driver.h C++/modules/Driver/DriverPostgres.cpp C++/modules/Driver/DriverPostgres.h C++/modules/Dynlib/Dynlib.cpp C++/modules/Dynlib/Dynlib.h C++/modules/Flags/Flags.h C++/modules/Hash/Hash.cpp C++/modules/Hash/Hash.h C++/modules/Ini/Ini.cpp C++/modules/Ini/Ini.h C++/modules/Json/Json.cpp C++/modules/Json/Json.h C++/modules/OptionParser/OptionParser.cpp C++/modules/OptionParser/OptionParser.h C++/modules/Pack/Pack.cpp C++/modules/Pack/Pack.h C++/modules/Parser/Parser.cpp C++/modules/Parser/Parser.h C++/modules/Socket/Socket.cpp C++/modules/Socket/Socket.h C++/modules/Socket/SocketAddress.cpp C++/modules/Socket/SocketAddress.h C++/modules/Socket/SocketListener.cpp C++/modules/Socket/SocketListener.h C++/modules/Socket/SocketSsl.cpp C++/modules/Socket/SocketSsl.h C++/modules/Socket/SocketTcp.cpp C++/modules/Socket/SocketTcp.h C++/modules/Socket/SocketUdp.cpp C++/modules/Socket/SocketUdp.h C++/modules/Treenode/TreeNode.h C++/modules/Utf8/Utf8.cpp C++/modules/Utf8/Utf8.h C++/modules/Xdg/Xdg.cpp C++/modules/Xdg/Xdg.h C++/modules/Zip/ZipArchive.cpp C++/modules/Zip/ZipArchive.h C++/tests/Base64/main.cpp C++/tests/Directory/main.cpp C++/tests/Dynlib/Plugin.cpp C++/tests/Dynlib/main.cpp C++/tests/Flags/main.cpp C++/tests/Hash/main.cpp C++/tests/Ini/configs/compact.conf C++/tests/Ini/configs/error-badcomment.conf C++/tests/Ini/configs/error-badsection.conf C++/tests/Ini/configs/error-lineassigment.conf C++/tests/Ini/configs/error-nosection.conf C++/tests/Ini/configs/includes.conf C++/tests/Ini/configs/multi.conf C++/tests/Ini/configs/novalue.conf C++/tests/Ini/configs/simple.conf C++/tests/Ini/configs/tokens.conf C++/tests/Ini/main.cpp C++/tests/Json/data/array-all.json C++/tests/Json/data/array.json C++/tests/Json/data/object-all.json C++/tests/Json/data/object.json C++/tests/Json/data/simple.json C++/tests/Json/main.cpp C++/tests/OptionParser/main.cpp C++/tests/Pack/main.cpp C++/tests/Parser/configs/multi.conf C++/tests/Parser/configs/simple.conf C++/tests/Parser/main.cpp C++/tests/Socket/main.cpp C++/tests/Treenode/main.cpp C++/tests/Utf8/main.cpp C++/tests/Xdg/main.cpp C++/tests/Zip/data/data.txt C++/tests/Zip/data/stats.zip C++/tests/Zip/main.cpp C/port/asprintf.c C/port/asprintf.h C/port/err.c C/port/err.h C/port/extern/getopt.c C/port/extern/getopt.h C/port/extern/queue.h C/port/extern/stdbool.h C/port/extern/strlcat.c C/port/extern/strlcpy.c C/port/setprogname.c C/port/setprogname.h C/port/strdup.c C/port/strdup.h C/port/strndup.c C/port/strndup.h C/port/strsep.c C/port/strsep.h CMakeLists.txt cmake/FindCppunit.cmake cmake/FindPandoc.cmake extern/gtest/CMakeLists.txt port/asprintf.c port/asprintf.h port/err.c port/err.h port/extern/getopt.c port/extern/getopt.h port/extern/queue.h port/extern/stdbool.h port/extern/strlcat.c port/extern/strlcpy.c port/setprogname.c port/setprogname.h port/strdup.c port/strdup.h port/strndup.c port/strndup.h port/strsep.c port/strsep.h tools/CMakeLists.txt tools/mdtohtml.cpp
diffstat 226 files changed, 24648 insertions(+), 24443 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Base64.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Base64.cpp -- base64 encoding and decoding
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iterator>
-#include <sstream>
-
-#include "Base64.h"
-
-char Base64::lookup(int value) noexcept
-{
-	static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-	return table[value];
-}
-
-int Base64::rlookup(char ch)
-{
-	if (ch == '+')
-		return 62;
-	if (ch == '/')
-		return 63;
-
-	if (ch >= '0' && ch <= '9')
-		return ch + 4;
-	if (ch >= 'A' && ch <= 'Z')
-		return ch - 65;
-	if (ch >= 'a' && ch <= 'z')
-		return ch - 71;
-
-	throw std::invalid_argument("not a valid base64 string");
-}
-
-std::string Base64::encode(const std::string &input)
-{
-	std::string result;
-	std::istringstream iss(input, std::istringstream::in);
-
-	encode(std::istreambuf_iterator<char>(iss), std::istreambuf_iterator<char>(), std::back_inserter(result));
-
-	return result;
-}
-
-std::string Base64::decode(const std::string &input)
-{
-	std::string result;
-	std::istringstream iss(input, std::istringstream::in);
-
-	decode(std::istreambuf_iterator<char>(iss), std::istreambuf_iterator<char>(), std::back_inserter(result));
-
-	return result;
-}
\ No newline at end of file
--- a/C++/Base64.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/*
- * Base64.h -- base64 encoding and decoding
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BASE_64_H_
-#define _BASE_64_H_
-
-/**
- * @file Base64.h
- * @brief Base64 encoding and decoding
- */
-
-#include <stdexcept>
-#include <string>
-
-/**
- * @class Base64
- * @brief Encode and decode Base64 data
- */
-class Base64 {
-public:
-	/**
-	 * Get the base 64 character from the 6-bits value.
-	 *
-	 * @param value the value
-	 */
-	static char lookup(int value) noexcept;
-
-	/**
-	 * Get the integer value from the base 64 character.
-	 *
-	 * @param ch the base64 character
-	 */
-	static int rlookup(char ch);
-
-	/**
-	 * Encode the input to the output. Requirements:
-	 *	InputIt	must be InputIterator
-	 *	OutputIt must be OutputIterator
-	 *
-	 * @param input the beginning
-	 * @param end the end of the data
-	 * @param output the output destination
-	 * @return output
-	 */
-	template <typename InputIt, typename OutputIt>
-	static OutputIt encode(InputIt input, InputIt end, OutputIt output)
-	{
-		while (input != end) {
-			char inputbuf[3] = { 0, 0, 0 };
-			int count;
-
-			for (count = 0; count < 3 && input != end; ++count)
-				inputbuf[count] = *input++;
-
-			*output++ = lookup(inputbuf[0] >> 2 & 0x3f);
-			*output++ = lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f));
-			*output++ = (count < 2) ? '=' : lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03));
-			*output++ = (count < 3) ? '=' : lookup(inputbuf[2] & 0x3f);
-		}
-
-		return output;
-	}
-
-	/**
-	 * Decode the input to the output. Requirements:
-	 *	InputIt must be InputIterator
-	 *	OutputIt must be OutputIterator
-	 *
-	 * @param input the beginning
-	 * @param end the end of the data
-	 * @param output the output destination
-	 * @return output
-	 * @throw std::invalid_argument on bad base64 string
-	 */
-	template <typename InputIt, typename OutputIt>
-	static OutputIt decode(InputIt input, InputIt end, OutputIt output)
-	{
-		while (input != end) {
-			char inputbuf[4] = { 0, 0, 0, 0 };
-			int count;
-
-			for (count = 0; count < 4 && input != end; ++count) {
-				inputbuf[count] = (*input == '=') ? '=' : rlookup(*input);
-				input++;
-			}
-
-			if (count != 4)
-				throw std::invalid_argument("truncated string");
-
-			*output++ = (inputbuf[0] << 2 & 0xfc) | (inputbuf[1] >> 4 & 0x03);
-
-			if (inputbuf[2] != '=')
-				*output++ = (inputbuf[1] << 4 & 0xf0) | (inputbuf[2] >> 2 & 0x0f);
-			if (inputbuf[3] != '=')
-				*output++ = (inputbuf[2] << 6 & 0xc0) | (inputbuf[3] & 0x3f);
-		}
-
-		return output;
-	}
-
-	/**
-	 * Encode a string.
-	 *
-	 * @param input the input string
-	 * @return the base64 formatted string
-	 */
-	static std::string encode(const std::string &input);
-
-	/**
-	 * Decode a string.
-	 *
-	 * @param input the base64 formatted string
-	 * @return the original string
-	 * @throw std::invalid_argument on bad base64 string
-	 */
-	static std::string decode(const std::string &input);
-};
-
-#endif // !_BASE_64_H_
--- a/C++/Converter.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Converter.cpp -- iconv based converter
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cerrno>
-#include <cstring>
-#include <string>
-#include <iterator>
-#include <memory>
-#include <string>
-#include <stdexcept>
-#include <vector>
-
-#include <iconv.h>
-
-#include "Converter.h"
-
-struct Deleter {
-	void operator()(iconv_t desc)
-	{
-		iconv_close(desc);
-	}
-};
-
-using Iconv = std::unique_ptr<std::remove_pointer<iconv_t>::type, Deleter>;
-
-std::string Converter::convert(const char *from,
-			       const char *to,
-			       const std::string &input)
-{
-	// No conversion if from and to are identical
-	if (std::strcmp(from, to) == 0)
-		return input;
-
-	// Try to open the conversion descriptor
-	auto cd = iconv_open(to, from);
-
-	if (cd == (iconv_t)-1)
-		throw std::invalid_argument(std::strerror(errno));
-
-	Iconv cv(cd);
-	std::size_t insize(input.size());
-	std::size_t outsize(insize);
-	std::vector<char> result(insize + 1);
-
-	auto *b = &input[0];
-	auto *p = &result[0];
-
-	while (insize > 0) {
-		/* Convert */
-		auto r = iconv(cv.get(), &b, &insize, &p, &outsize);
-
-		if (r == (size_t)-1) {
-			switch (errno) {
-			case EBADF:
-			case EILSEQ:
-			case EINVAL:
-				throw std::invalid_argument(std::strerror(errno));
-			case E2BIG:
-				/*
-				 * Here, we need to reallocate more data because the output
-				 * string may need more space.
-				 *
-				 * We use 16 as an optimistic value.
-				 */
-
-				result.reserve(result.size() + 16 + 1);
-				p = &result[result.size()];
-				outsize += 16;
-			default:
-				break;
-			}
-		}
-
-	}
-
-	return std::string(&result[0], (p - &result[0]));
-}
--- a/C++/Converter.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Converter.h -- iconv based converter
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _CONVERTER_H_
-#define _CONVERTER_H_
-
-/**
- * @file Converter.h
- * @brief Converter using libiconv
- */
-
-#include <string>
-
-/**
- * @class Converter
- * @brief Convert string between different encodings
- */
-class Converter {
-public:
-	/**
-	 * Convert the string into a different encoding.
-	 *
-	 * @param from the from encoding
-	 * @param to the destination encoding
-	 * @param input the string to convert
-	 * @return the converted string
-	 * @throw std::invalid_argument on invalid sequence
-	 */
-	static std::string convert(const char *from,
-				   const char *to,
-				   const std::string &input);
-};
-
-#endif // !_CONVERTER_H_
--- a/C++/Date.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Date.cpp -- date and time manipulation
- *
- * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "Date.h"
-
-Date::Date()
-{
-	m_timestamp = time(NULL);
-}
-
-Date::Date(time_t timestamp)
-{
-	m_timestamp = timestamp;
-}
-
-Date::~Date()
-{
-}
-
-time_t Date::getTimestamp() const
-{
-	return m_timestamp;
-}
-
-std::string Date::format(const std::string &format)
-{
-	char buffer[512];
-	struct tm *tm;
-
-	tm = localtime(&m_timestamp);
-	strftime(buffer, sizeof (buffer), format.c_str(), tm);
-
-	return std::string(buffer);
-}
-
-bool operator==(const Date &d1, const Date &d2)
-{
-	return d1.getTimestamp() == d2.getTimestamp();
-}
-
-bool operator<=(const Date &d1, const Date &d2)
-{
-	return d1.getTimestamp() <= d2.getTimestamp();
-}
--- a/C++/Date.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Date.h -- date and time manipulation
- *
- * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _DATE_H_
-#define _DATE_H_
-
-#include <cstdint>
-#include <ctime>
-#include <string>
-
-struct Date
-{
-	time_t m_timestamp;		//! time epoch
-
-	Date();
-	Date(time_t timestamp);
-	~Date();
-
-	/**
-	 * Get the timestamp.
-	 *
-	 * @return the timestamp
-	 */
-	time_t getTimestamp() const;
-
-	/**
-	 * Format the current that in the specified format,
-	 * see strftime(3) for patterns.
-	 *
-	 * @param format the format
-	 * @return the date formated
-	 */
-	std::string format(const std::string &format);
-};
-
-bool operator==(const Date &, const Date &);
-
-bool operator<=(const Date &, const Date &);
-
-#endif // !_DATE_H_
--- a/C++/Directory.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * Directory.cpp -- open and read directories
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sstream>
-#include <stdexcept>
-
-#include "Directory.h"
-
-#if defined(_WIN32)
-#  include <Windows.h>
-#else
-#  include <cstring>
-#  include <cerrno>
-
-#  include <sys/types.h>
-#  include <dirent.h>
-#endif
-
-#if defined(_WIN32)
-
-namespace {
-
-std::string systemError()
-{
-	LPSTR error = nullptr;
-	std::string errmsg = "Unknown error";
-
-	FormatMessageA(
-		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-		NULL,
-		GetLastError(),
-		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-		(LPSTR)&error, 0, NULL);
-
-	if (error) {
-		errmsg = std::string(error);
-		LocalFree(error);
-	}
-
-	return errmsg;
-}
-
-}
-
-void Directory::systemLoad(const std::string &path, int flags)
-{
-	std::ostringstream oss;
-	HANDLE handle;
-	WIN32_FIND_DATA fdata;
-
-	oss << path << "\\*";
-	handle = FindFirstFile(oss.str().c_str(), &fdata);
-
-	if (handle == nullptr)
-		throw std::runtime_error(systemError());
-
-	do {
-		Entry entry;
-
-		entry.name = fdata.cFileName;
-		if ((flags & Directory::NotDot) && entry.name == ".")
-			continue;
-		if ((flags & Directory::NotDotDot) && entry.name == "..")
-			continue;
-
-		switch (fdata.dwFileAttributes) {
-		case FILE_ATTRIBUTE_DIRECTORY:
-			entry.type = Dir;
-			break;
-		case FILE_ATTRIBUTE_NORMAL:
-			entry.type = File;
-			break;
-		case FILE_ATTRIBUTE_REPARSE_POINT:
-			entry.type = Link;
-			break;
-		default:
-			break;
-		}
-
-		m_list.push_back(entry);
-	} while (FindNextFile(handle, &fdata) != 0);
-
-	FindClose(handle);
-}
-
-#else
-
-void Directory::systemLoad(const std::string &path, int flags)
-{
-	DIR *dp;
-	struct dirent *ent;
-
-	if ((dp = opendir(path.c_str())) == nullptr)
-		throw std::runtime_error(strerror(errno));
-
-	while ((ent = readdir(dp)) != nullptr) {
-		Entry entry;
-
-		entry.name = ent->d_name;
-		if ((flags & Directory::NotDot) && entry.name == ".")
-			continue;
-		if ((flags & Directory::NotDotDot) && entry.name == "..")
-			continue;
-
-		switch (ent->d_type) {
-		case DT_DIR:
-			entry.type = Dir;
-			break;
-		case DT_REG:
-			entry.type = File;
-			break;
-		case DT_LNK:
-			entry.type = Link;
-			break;
-		default:
-			break;
-		}
-
-		m_list.push_back(entry);
-	}
-
-	closedir(dp);
-}
-
-#endif
-
-Directory::Entry::Entry()
-	: type(Unknown)
-{
-}
-
-bool operator==(const Directory::Entry &e1, const Directory::Entry &e2)
-{
-	return e1.name == e2.name && e1.type == e2.type;
-}
-
-Directory::Directory()
-{
-}
-
-Directory::Directory(const std::string &path, int flags)
-{
-	systemLoad(path, flags);
-}
-
-Directory::List::iterator Directory::begin()
-{
-	return m_list.begin();
-}
-
-Directory::List::const_iterator Directory::cbegin() const
-{
-	return m_list.cbegin();
-}
-
-Directory::List::iterator Directory::end()
-{
-	return m_list.end();
-}
-
-Directory::List::const_iterator Directory::cend() const
-{
-	return m_list.cend();
-}
-
-int Directory::count() const
-{
-	return m_list.size();
-}
-
-bool operator==(const Directory &d1, const Directory &d2)
-{
-	return d1.m_list == d2.m_list;
-}
--- a/C++/Directory.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
- * Directory.h -- open and read directories
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _DIRECTORY_H_
-#define _DIRECTORY_H_
-
-#include <cstddef>
-#include <string>
-#include <vector>
-
-/**
- * @class Directory
- * @brief class to manipulate directories
- *
- * This class allow the user to iterate directories in a for range based
- * loop using iterators.
- */
-class Directory {
-public:
-	/**
-	 * @enum Flags
-	 * @brief optional flags to read directories
-	 */
-	enum Flags {
-		NotDot		= (1 << 0),
-		NotDotDot	= (1 << 1)
-	};
-
-	/**
-	 * @enum Type
-	 * @brief Describe the type of an entry
-	 */
-	enum Type {
-		Unknown		= 0,
-		File,
-		Dir,
-		Link
-	};
-
-	/**
-	 * @struct Entry
-	 * @brief entry in the directory list
-	 */
-	struct Entry {
-		std::string	name;		//! name of entry (base name)
-		Type		type;		//! type of file
-
-		Entry();
-
-		friend bool operator==(const Entry &e1, const Entry &e2);
-	};
-
-	using List = std::vector<Entry>;
-
-	// C++ Container compatibility
-	using value_type	= List::value_type;
-	using iterator		= List::iterator;
-	using const_iterator	= List::const_iterator;
-
-private:
-	List m_list;
-
-	void systemLoad(const std::string &path, int flags);
-
-public:
-	/**
-	 * Default constructor, does nothing.
-	 */
-	Directory();
-
-	/**
-	 * Open a directory and read all its content.
-	 * @param path the path
-	 * @param flags the optional flags
-	 */
-	Directory(const std::string &path, int flags = 0);
-
-	/**
-	 * Return an iterator the beginning.
-	 *
-	 * @return the iterator
-	 */
-	List::iterator begin();
-
-	/**
-	 * Return a const iterator the beginning.
-	 *
-	 * @return the iterator
-	 */
-	List::const_iterator cbegin() const;
-
-	/**
-	 * Return an iterator to past the end.
-	 *
-	 * @return the iterator
-	 */
-	List::iterator end();
-
-	/**
-	 * Return a const iterator to past the end.
-	 *
-	 * @return the iterator
-	 */
-	List::const_iterator cend() const;
-
-	/**
-	 * Get the number of entries in the directory.
-	 *
-	 * @return the number
-	 */
-	int count() const;
-
-	friend bool operator==(const Directory &d1, const Directory &d2);
-};
-
-#endif // !_DIRECTORY_H_
--- a/C++/Driver.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Driver.cpp -- generic SQL driver access
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdexcept>
-#include <sstream>
-
-#include "Driver.h"
-
-/* ---------------------------------------------------------
- * DriverQuery class
- * ---------------------------------------------------------*/
-
-DriverQuery::DriverQuery(Ptr impl)
-	: m_impl(impl)
-{
-}
-
-void DriverQuery::assertRequest(int row, const std::string &column, DriverColumn wanted)
-{
-	std::ostringstream oss;
-
-	// Out of bounds?
-	if (row < 0 || row >= countRows()) {
-		oss << "Invalid row index " << row;
-		oss << ", expected [0.." << countRows() << "]";
-
-		throw std::runtime_error(oss.str());
-	}
-
-	// Not found or bad column?
-	if (type(column) != wanted) {
-		oss << "Invalid or not found column `" << column << "'";
-
-		throw std::runtime_error(oss.str());
-	}
-}
-
-DriverQuery::~DriverQuery()
-{
-}
-
-DriverColumn DriverQuery::type(const std::string &column) const
-{
-	return m_impl->type(column);
-}
-
-int DriverQuery::countRows()
-{
-	return m_impl->countRows();
-}
-
-int DriverQuery::countColumns()
-{
-	return m_impl->countColumns();
-}
-
-bool DriverQuery::isNull(int row, const std::string &column)
-{
-	return m_impl->isNull(row, column);
-}
-
-void DriverQuery::dump()
-{
-	m_impl->dump();
-}
-
-/* --------------------------------------------------------
- * DriverRequest class
- * -------------------------------------------------------- */
-
-DriverRequest::DriverRequest(Ptr impl, const std::string &command)
-	: m_pos(0)
-	, m_params(0)
-	, m_command(command)
-	, m_impl(impl)
-{
-	int i = -1;
-
-	while ((i = command.find('#', i + 1)) != std::string::npos)
-		++ m_params;
-}
-
-DriverRequest::~DriverRequest()
-{
-}
-
-void DriverRequest::assertCorrect()
-{
-	if (m_params <= 0)
-		throw std::runtime_error("no more arguments to set");
-}
-
-void DriverRequest::setValue(const std::string &value)
-{
-	assertCorrect();
-
-	m_pos = m_command.find('#', m_pos);
-	m_command.replace(m_pos, 1, value);
-	m_pos += value.length();
-	m_params --;
-}
-
-DriverRequest::operator std::string()
-{
-	return m_command;
-}
-
-/* --------------------------------------------------------
- * Driver class
- * -------------------------------------------------------- */
-
-void Driver::connect(const Params &params)
-{
-	m_impl->connect(params);
-}
-
-DriverRequest Driver::prepare(const std::string &command)
-{
-	return m_impl->prepare(command);
-}
-
-DriverQuery Driver::query(const std::string &sql)
-{
-	return m_impl->query(sql);
-}
-
-DriverQuery Driver::query(DriverRequest request)
-{
-	return query(static_cast<std::string>(request));
-}
-
-std::string Driver::description() const
-{
-	return m_impl->description();
-}
-
-std::string Driver::version() const
-{
-	return m_impl->version();
-}
--- a/C++/Driver.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,529 +0,0 @@
-/*
- * Driver.h -- generic SQL driver access
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _DRIVER_H_
-#define _DRIVER_H_
-
-#include <ctime>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <type_traits>
-
-/**
- * @enum DriverColumn
- * @brief The column type request
- *
- * Used for the drivers.
- */
-enum class DriverColumn {
-	Invalid,			//! not found
-	Boolean,			//! bool or 0 / 1
-	Date,				//! date see Common/Date.h
-	Double,				//! double
-	Integer,			//! 32 or 64 bit int
-	String,				//! varchar to std::string
-};
-
-template <typename T>
-struct DriverTypeInfo : std::false_type { };
-
-/**
- * @class Query
- * @brief Class for querying the database
- *
- * That class is returned when a SQL query succeed. It can retrieve the
- * number of rows, columns and retrieve the results independantly from the
- * driver.
- *
- * @see Driver::query
- */
-class DriverQuery {
-public:
-	friend struct DriverTypeInfo<bool>;
-	friend struct DriverTypeInfo<time_t>;
-	friend struct DriverTypeInfo<double>;
-	friend struct DriverTypeInfo<int>;
-	friend struct DriverTypeInfo<std::string>;
-
-	class Impl {
-	public:
-		/**
-		 * Get a bool.
-		 *
-		 * @param row the row number
-		 * @param column the column
-		 * @return the value
-		 */
-		virtual bool getBoolean(int row, const std::string &column) = 0;
-
-		/**
-		 * Get a Date.
-		 *
-		 * @param row the row number
-		 * @param column the column
-		 * @return the value
-		 */
-		virtual time_t getDate(int row, const std::string &column) = 0;
-
-		/**
-		 * Get a double.
-		 *
-		 * @param row the row number
-		 * @param column the column
-		 * @return the value
-		 */
-		virtual double getDouble(int row, const std::string &column) = 0;
-
-		/**
-		 * Get a integer.
-		 *
-		 * @param row the row number
-		 * @param column the column
-		 * @return the value
-		 */
-		virtual int getInt(int row, const std::string &column) = 0;
-
-		/**
-		 * Get a string.
-		 *
-		 * @param row the row number
-		 * @param column the column
-		 * @return the value
-		 */
-		virtual std::string getString(int row, const std::string &column) = 0;
-
-		/**
-		 * Returns the type of a named column.
-		 *
-		 * @param column the column name
-		 * @return the type
-		 */
-		virtual DriverColumn type(const std::string &column) const = 0;
-
-		/**
-		 * Tells how many rows has been fetched.
-		 *
-		 * @return the number of rows
-		 */
-		virtual int countRows() = 0;
-
-		/**
-		 * Tells how many number of columns are present for each
-		 * row.
-		 *
-		 * @return the number of columns
-		 */
-		virtual int countColumns() = 0;
-
-		/**
-		 * Tells if the column is null or not.
-		 *
-		 * @param row the row number
-		 * @param column the column
-		 * @return an true if null
-		 */
-		virtual bool isNull(int row, const std::string &column) = 0;
-
-		/**
-		 * Dump all rows and columns.
-		 */
-		virtual void dump() = 0;
-	};
-
-	using Ptr	= std::shared_ptr<Impl>;
-
-private:
-	/**
-	 * Check if the request is valid and throws an exception
-	 * on error.
-	 *
-	 * @param row the row number
-	 * @param column the column name
-	 * @param type
-	 * @throw Error on error
-	 */
-	void assertRequest(int row, const std::string &column, DriverColumn type);
-
-protected:
-	Ptr		m_impl;
-
-public:
-	DriverQuery(Ptr impl);
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~DriverQuery();
-
-	/**
-	 * Get a variable from a row and column.
-	 *
-	 * Specialization available:
-	 *	- bool
-	 *	- Date
-	 *	- double
-	 *	- int
-	 *	- std::string
-	 *
-	 * @param row the row number (starts from 0)
-	 * @param column the the column name
-	 * @return the value
-	 * @throw Query::Error on error
-	 */
-	template <class T>
-	T get(int row, const std::string &column)
-	{
-		static_assert(DriverTypeInfo<T>::value, "unsupported type");
-
-		assertRequest(row, column, DriverTypeInfo<T>::type);
-	
-		return DriverTypeInfo<T>::get(*this, row, column);
-	}
-
-	/**
-	 * Returns the type of a named column.
-	 *
-	 * @param column the column name
-	 * @return the type
-	 */
-	DriverColumn type(const std::string &column) const;
-
-	/**
-	 * Tells how many rows has been fetched.
-	 *
-	 * @return the number of rows
-	 */
-	int countRows();
-
-	/**
-	 * Tells how many number of columns are present for each
-	 * row.
-	 *
-	 * @return the number of columns
-	 */
-	int countColumns();
-
-	/**
-	 * Tells if the column is null or not.
-	 *
-	 * @param row the row number
-	 * @param column the column
-	 * @return an true if null
-	 */
-	bool isNull(int row, const std::string &column);
-
-	/**
-	 * Dump all rows and columns.
-	 */
-	void dump();
-};
-
-/**
- * @class Request
- * @brief A secure helper for creating requests
- *
- * This helps creating class with SQL injection security and such.
- */
-class DriverRequest {
-public:
-	friend struct DriverTypeInfo<bool>;
-	friend struct DriverTypeInfo<time_t>;
-	friend struct DriverTypeInfo<double>;
-	friend struct DriverTypeInfo<int>;
-	friend struct DriverTypeInfo<std::string>;
-
-	class Impl {
-	public:
-		/**
-		 * Bind a boolean.
-		 *
-		 * @param value the boolean
-		 * @return the string to use
-		 */
-		virtual std::string bindBoolean(bool value) = 0;
-
-		/**
-		 * Bind a date.
-		 *
-		 * @param value the date
-		 * @return the string to use
-		 */
-		virtual std::string bindDate(time_t value) = 0;
-
-		/**
-		 * Bind a double.
-		 *
-		 * @param value the double
-		 * @return the string to use
-		 */
-		virtual std::string bindDouble(double value) = 0;
-
-		/**
-		 * Bind an integer.
-		 *
-		 * @param value the integer
-		 * @return the string to use
-		 */
-		virtual std::string bindInteger(int value) = 0;
-
-		/**
-		 * Bind a string.
-		 *
-		 * @param value the string
-		 * @return the string to use
-		 */
-		virtual std::string bindString(std::string value) = 0;
-	};
-
-	using Ptr	= std::shared_ptr<Impl>;
-
-private:
-	size_t		m_pos;
-	int		m_params;
-	std::string	m_command;
-	Ptr		m_impl;
-
-	void assertCorrect();
-
-	void setValue(const std::string &value);
-
-public:
-	DriverRequest(Ptr impl, const std::string &command);
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~DriverRequest();
-
-	/**
-	 * Bind a value.
-	 *
-	 * @param value the value
-	 */
-	template <typename T>
-	void bind(T value)
-	{
-		static_assert(DriverTypeInfo<T>::value, "unsupported type");
-
-		setValue(DriverTypeInfo<T>::bind(value));
-	}
-
-	/**
-	 * Convert the request to string.
-	 *
-	 * @return the request as a string
-	 */
-	operator std::string();
-};
-
-/**
- * @class Driver
- * @brief A generic SQL driver
- *
- * This class is used to connect to a database and execute SQL queries. It
- * does not include any DBMS code and just call virtual functions for
- * a simpler integration of new DBMS drivers.
- */
-class Driver {
-public:
-	class Impl;
-
-	using Params	= std::unordered_map<std::string, std::string>;
-	using Ptr	= std::shared_ptr<Impl>;
-
-	class Impl {
-	public:
-		/**
-		 * Create a synchronous connection, it waits and block until
-		 * the connection is made up to a specified timeout max.
-		 *
-		 * @param params a list of parameters.
-		 */
-		virtual void connect(const Params &params) = 0;
-
-		/**
-		 * Prepare a request with the specified SQL command.
-		 *
-		 * @param command the SQL command to parse and bind
-		 * @return a request to use with query
-		 * @see query
-		 */
-		virtual DriverRequest prepare(const std::string &command) = 0;
-	
-		/**
-		 * Execute a query.
-		 *
-		 * @param query the SQL command
-		 * @return a result
-		 * @throw Query::Error on failure
-		 */
-		virtual DriverQuery query(const std::string &command) = 0;
-
-		/**
-		 * Get the driver connection description.
-		 *
-		 * @return the description
-		 */
-		virtual std::string description() const = 0;
-
-		/**
-		 * Get the driver version as a string.
-		 *
-		 * @return the version
-		 */
-		virtual std::string version() const = 0;
-	};
-
-protected:
-	Ptr		m_impl;
-
-public:
-	Driver() = default;
-
-	/**
-	 * Virtual destructor.
-	 */
-	virtual ~Driver() = default;
-
-	/**
-	 * Wrapper for std::string variant.
-	 *
-	 * @param request the request to use
-	 * @return a result
-	 * @throw Query::Error on failure
-	 */
-	DriverQuery query(DriverRequest request);
-
-	/**
-	 * Create a synchronous connection, it waits and block until
-	 * the connection is made up to a specified timeout max.
-	 *
-	 * @param params a list of parameters.
-	 */
-	void connect(const Params &params);
-
-	/**
-	 * Prepare a request with the specified SQL command.
-	 *
-	 * @param command the SQL command to parse and bind
-	 * @return a request to use with query
-	 * @see query
-	 */
-	DriverRequest prepare(const std::string &command);
-
-	/**
-	 * Execute a query.
-	 *
-	 * @param query the SQL command
-	 * @return a result
-	 * @throw Query::Error on failure
-	 */
-	DriverQuery query(const std::string &command);
-
-	/**
-	 * Get the driver connection description.
-	 *
-	 * @return the description
-	 */
-	std::string description() const;
-
-	/**
-	 * Get the driver version as a string.
-	 *
-	 * @return the version
-	 */
-	std::string version() const;
-};
-
-template <>
-struct DriverTypeInfo<bool> : std::true_type {
-	static const DriverColumn	type = DriverColumn::Boolean;
-
-	static bool get(DriverQuery &query, int row, const std::string &column)
-	{
-		return query.m_impl->getBoolean(row, column);
-	}
-
-	static void bind(DriverRequest &request, bool value)
-	{
-		request.m_impl->bindBoolean(value);
-	}
-};
-
-template <>
-struct DriverTypeInfo<time_t> : std::true_type {
-	static const DriverColumn	type = DriverColumn::Date;
-
-	static time_t get(DriverQuery &query, int row, const std::string &column)
-	{
-		return query.m_impl->getDate(row, column);
-	}
-
-	static void bind(DriverRequest &request, time_t value)
-	{
-		request.m_impl->bindDate(value);
-	}
-};
-
-template <>
-struct DriverTypeInfo<double> : std::true_type {
-	static const DriverColumn	type = DriverColumn::Double;
-
-	static double get(DriverQuery &query, int row, const std::string &column)
-	{
-		return query.m_impl->getDouble(row, column);
-	}
-
-	static void bind(DriverRequest &request, double value)
-	{
-		request.m_impl->bindDouble(value);
-	}
-};
-
-template <>
-struct DriverTypeInfo<int> : std::true_type {
-	static const DriverColumn	type = DriverColumn::Integer;
-
-	static int get(DriverQuery &query, int row, const std::string &column)
-	{
-		return query.m_impl->getInt(row, column);
-	}
-
-	static void bind(DriverRequest &request, int value)
-	{
-		request.m_impl->bindInteger(value);
-	}
-};
-
-template <>
-struct DriverTypeInfo<std::string> : std::true_type {
-	static const DriverColumn	type = DriverColumn::String;
-
-	static std::string get(DriverQuery &query, int row, const std::string &column)
-	{
-		return query.m_impl->getString(row, column);
-	}
-
-	static void bind(DriverRequest &request, const std::string &value)
-	{
-		request.m_impl->bindString(value);
-	}
-};
-
-#endif // !_DRIVER_H_
--- a/C++/DriverPostgres.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,482 +0,0 @@
-/*
- * DriverPostgres.cpp -- PostgreSQL driver
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cerrno>
-#include <cstring>
-#include <iostream>
-#include <stdexcept>
-#include <sstream>
-#include <vector>
-
-#include <libpq-fe.h>
-
-#include "DriverPostgres.h"
-
-namespace {
-
-using PostgresResult	= std::shared_ptr<PGresult>;
-using PostgresConn	= std::shared_ptr<PGconn>;
-
-}
-
-/**
- * @class QueryPostgres
- * @brief Query implementation for PostgreSQL.
- */
-class QueryPostgresImpl : public DriverQuery::Impl {
-private:
-	PostgresConn	m_connection;
-	PostgresResult	m_result;
-
-public:
-	/**
-	 * Constructor used by DriverPostgres
-	 *
-	 * @param result the result
-	 */
-	QueryPostgresImpl(PostgresConn conn, PostgresResult result);
-
-	/**
-	 * @copydoc Query::getBoolean
-	 */
-	virtual bool getBoolean(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getDate
-	 */
-	virtual time_t getDate(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getDouble
-	 */
-	virtual double getDouble(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getInt
-	 */
-	virtual int getInt(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getString
-	 */
-	virtual std::string getString(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::type
-	 */
-	virtual DriverColumn type(const std::string &column) const;
-
-	/**
-	 * @copydoc Query::countRows
-	 */
-	virtual int countRows();
-
-	/**
-	 * @copydoc Query::countColumns
-	 */
-	virtual int countColumns();
-
-	/**
-	 * @copydoc Query::isNull
-	 */
-	virtual bool isNull(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::dump
-	 */
-	virtual void dump();
-};
-
-QueryPostgresImpl::QueryPostgresImpl(PostgresConn conn, PostgresResult result)
-	: m_connection(conn)
-	, m_result(result)
-{
-}
-
-DriverColumn QueryPostgresImpl::type(const std::string &column) const
-{
-	DriverColumn type;
-	int pqType, index;
-	
-	index = PQfnumber(m_result.get(), column.c_str());
-	pqType = PQftype(m_result.get(), index);
-	switch (pqType) {
-	case 16:
-		type = DriverColumn::Boolean;
-		break;
-	case 1082:
-	case 1083:
-	case 1114:
-	case 1184:
-		type = DriverColumn::Date;
-		break;
-	case 1700:
-	case 700:
-	case 701:
-		type = DriverColumn::Double;
-		break;
-	case 20:
-	case 21:
-	case 23:
-		type = DriverColumn::Integer;
-		break;
-	case 25:
-	case 1042:
-	case 1043:
-		type = DriverColumn::String;
-		break;
-	default:
-		type = DriverColumn::Invalid;
-	}
-
-	return type;
-}
-
-int QueryPostgresImpl::countRows()
-{
-	return PQntuples(m_result.get());
-}
-
-int QueryPostgresImpl::countColumns()
-{
-	return PQnfields(m_result.get());
-}
-
-bool QueryPostgresImpl::isNull(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-
-	return PQgetisnull(m_result.get(), row, idx) == 1;
-}
-
-void QueryPostgresImpl::dump(void)
-{
-	std::cout << "Dumping PostgreSQL result, ";
-	std::cout << countRows() << " rows, ";
-	std::cout << countColumns() << " columns" << std::endl;
-
-	for (int r = 0; r < countRows(); ++r) {
-		std::cout << "Dumping row " << r << std::endl;
-		std::cout << "==============================" << std::endl;
-
-		for (int c = 0; c < countColumns(); ++c) {
-			std::cout << "\t" << PQfname(m_result.get(), c);
-			std::cout << " = " << PQgetvalue(m_result.get(), r, c) << std::endl;
-		}
-	}
-}
-
-bool QueryPostgresImpl::getBoolean(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-	std::string code = PQgetvalue(m_result.get(), row, idx);
-
-	return code[0] == 't';
-}
-
-time_t QueryPostgresImpl::getDate(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-	time_t timestamp = std::time(nullptr);
-
-	try {
-		std::ostringstream oss;
-		std::string value, req;
-
-		value = PQgetvalue(m_result.get(), row, idx);
-
-		/*
-		 * Convert the date using the SQL function so that user does
-		 * not require any explicit conversion itself.
-		 */
-		printf("%s\n", value.c_str());
-		oss << "Select EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '";
-		oss << value;
-		oss << "') AS RESULT";
-		req = oss.str();
-
-		auto info = PQexec(m_connection.get(), oss.str().c_str());
-		auto status = PQresultStatus(info);
-
-		if (info != nullptr && (status == PGRES_COMMAND_OK ||
-		    status == PGRES_TUPLES_OK))
-		{
-			timestamp = atoi(PQgetvalue(info, 0, 0));
-			PQclear(info);
-		}
-	} catch (...) { }
-
-	return timestamp;
-}
-
-double QueryPostgresImpl::getDouble(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-
-	return std::stod(PQgetvalue(m_result.get(), row, idx));
-}
-
-int QueryPostgresImpl::getInt(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-
-	return std::stoi(PQgetvalue(m_result.get(), row, idx));
-}
-
-std::string QueryPostgresImpl::getString(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-
-	return std::string(PQgetvalue(m_result.get(), row, idx));
-}
-
-/* --------------------------------------------------------
- * Request PostgreSQL Impl
- * -------------------------------------------------------- */
-
-/**
- * @class RequestPostgres
- * @brief Request implementation for PostgreSQL.
- */
-class RequestPostgres : public DriverRequest::Impl {
-private:
-	std::shared_ptr<PGconn> m_connection;
-
-protected:
-	/**
-	 * @copydoc Request::bindBoolean
-	 */
-	virtual std::string bindBoolean(bool value);
-
-	/**
-	 * @copydoc Request::bindDate
-	 */
-	virtual std::string bindDate(time_t value);
-
-	/**
-	 * @copydoc Request::bindDouble
-	 */
-	virtual std::string bindDouble(double value);
-
-	/**
-	 * @copydoc Request::bindInteger
-	 */
-	virtual std::string bindInteger(int value);
-
-	/**
-	 * @copydoc Request::bindString
-	 */
-	virtual std::string bindString(std::string value);
-
-public:
-	/**
-	 * Construct a request for PostgreSQL.
-	 *
-	 * @param conn the connection
-	 * @param command the command
-	 */
-	RequestPostgres(PostgresConn &conn);
-};
-
-RequestPostgres::RequestPostgres(PostgresConn &conn)
-{
-	m_connection = conn;
-}
-
-std::string RequestPostgres::bindBoolean(bool value)
-{
-	return (value) ? "'t'" : "'f'";
-}
-
-std::string RequestPostgres::bindDate(time_t value)
-{
-	std::ostringstream oss;
-
-	oss << "to_timestamp(" << value << ")";
-
-	return oss.str();
-}
-
-std::string RequestPostgres::bindDouble(double value)
-{
-	return std::to_string(value);
-}
-
-std::string RequestPostgres::bindInteger(int value)
-{
-	return std::to_string(value);
-}
-
-std::string RequestPostgres::bindString(std::string value)
-{
-	std::string result;
-	char *tmp;
-
-	tmp = PQescapeLiteral(m_connection.get(), value.c_str(), value.length());
-	if (tmp == nullptr)
-		return "";
-
-	result = std::string(tmp);
-	PQfreemem(tmp);
-
-	return result;
-}
-
-/* --------------------------------------------------------
- * Driver PostgreSQL impl
- * -------------------------------------------------------- */
-
-/**
- * @class DriverPostgres
- * @brief Driver implementation for PostgreSQL.
- */
-class DriverPostgresImpl : public Driver::Impl {
-private:
-	PostgresConn m_connection;
-
-	/**
-	 * Convert the Params from the config
-	 * to the PostgreSQL string.
-	 *
-	 * @param settings the table
-	 * @return a string to be used
-	 */
-	std::string convert(Driver::Params &settings);
-
-public:
-	/**
-	 * @copydoc Driver::connect
-	 */
-	virtual void connect(const Driver::Params &params);
-
-	/**
-	 * @copydoc Driver::prepare
-	 */
-	virtual DriverRequest prepare(const std::string &command);
-
-	/**
-	 * @copydoc Driver::query
-	 */
-	virtual DriverQuery query(const std::string &command);
-
-	/**
-	 * @copydoc Driver::description
-	 */
-	virtual std::string description() const;
-
-	/**
-	 * @copydoc Driver::version
-	 */
-	virtual std::string version() const;
-};
-
-std::string DriverPostgresImpl::convert(Driver::Params &params)
-{
-	std::ostringstream oss;
-	std::vector<std::string> required { "host", "port", "user", "database", "password" };
-
-	for (auto s : required)
-		if (params.count(s) <= 0)
-			throw std::runtime_error("missing parameter " + s);
-
-	oss << "host = " << params["host"] << " ";
-	oss << "port = " << params["port"] << " ";
-	oss << "user = " << params["user"] << " ";
-	oss << "dbname = " << params["database"] << " ";
-	oss << "password = " << params["password"];
-
-	return oss.str();
-}
-
-void DriverPostgresImpl::connect(const Driver::Params &params)
-{
-	auto copy = params;
-	auto conn = PQconnectdb(convert(copy).c_str());
-
-	if (conn == nullptr)
-		throw std::runtime_error(std::strerror(ENOMEM));
-
-	if (PQstatus(conn) == CONNECTION_BAD) {
-		auto error = PQerrorMessage(conn);
-		PQfinish(conn);
-
-		throw std::runtime_error(error);
-	}
-
-	m_connection = std::shared_ptr<PGconn>(conn, PQfinish);
-}
-
-DriverRequest DriverPostgresImpl::prepare(const std::string &command)
-{
-	return DriverRequest(std::make_shared<RequestPostgres>(m_connection), command);
-}
-
-DriverQuery DriverPostgresImpl::query(const std::string &cmd)
-{
-	PGresult *info;
-
-	// If NULL, the libpq said no memory
-	info = PQexec(m_connection.get(), cmd.c_str());
-	if (info == nullptr)
-		throw std::runtime_error(strerror(ENOMEM));
-
-	// If an error occured
-	int errorCode = PQresultStatus(info);
-	if (errorCode != PGRES_COMMAND_OK && errorCode != PGRES_TUPLES_OK) {
-		auto error = PQresultErrorMessage(info);
-		PQclear(info);
-
-		throw std::runtime_error(error);
-	}
-
-	auto result = std::shared_ptr<PGresult>(info, PQclear);
-	auto impl = std::make_shared<QueryPostgresImpl>(m_connection, result);
-
-	return DriverQuery(impl);
-}
-
-std::string DriverPostgresImpl::description() const
-{
-	std::ostringstream oss;
-
-	oss << "Connected on PostgreSQL database: " << std::endl;
-	oss << "  host: " << PQhost(m_connection.get()) << std::endl;
-	oss << "  port: " << PQport(m_connection.get()) << std::endl;
-	oss << "  user: " << PQuser(m_connection.get()) << std::endl;
-	oss << "  database: " << PQdb(m_connection.get()) << std::endl;
-
-	return oss.str();
-}
-
-std::string DriverPostgresImpl::version() const
-{
-	std::ostringstream oss;
-
-	oss << "PostgreSQL driver (version " << PQlibVersion() << ")";
-
-	return oss.str();
-}
-
-/* --------------------------------------------------------
- * Driver PostgreSQL
- * -------------------------------------------------------- */
-
-DriverPostgres::DriverPostgres()
-{
-	m_impl = std::make_shared<DriverPostgresImpl>();
-}
--- a/C++/DriverPostgres.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * DriverPostgres.h -- PostgreSQL driver
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS
- */
-
-#ifndef _DRIVER_PG_H_
-#define _DRIVER_PG_H_
-
-#include "Driver.h"
-
-class DriverPostgres : public Driver {
-public:
-	DriverPostgres();
-};
-
-#endif // !_DRIVER_PG_H_
--- a/C++/DynLib.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-/*
- * DynLib.cpp -- portable shared library loader
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdexcept>
-
-#if defined(_WIN32)
-#  include <Windows.h>
-#else
-#  include <dlfcn.h>
-#endif
-
-#include "DynLib.h"
-
-#if defined(_WIN32)
-
-namespace {
-
-std::string systemError()
-{
-	LPSTR error = nullptr;
-	std::string errmsg = "Unknown error";
-
-	FormatMessageA(
-		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-		NULL,
-		GetLastError(),
-		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-		(LPSTR)&error, 0, NULL);
-
-	if (error) {
-		errmsg = std::string(error);
-		LocalFree(error);
-	}
-
-	return errmsg;
-}
-
-}
-
-void DynLib::systemInit()
-{
-	m_handle = nullptr;
-}
-
-DynLib::Handle DynLib::systemLoad(const std::string &path, Policy policy) const
-{
-	Handle handle = LoadLibraryA(path.c_str());
-
-	if (handle == nullptr)
-		throw std::runtime_error(systemError());
-
-	return handle;
-}
-
-DynLib::Sym DynLib::systemSym(const std::string &name)
-{
-	Sym sym;
-
-	if (m_handle == nullptr)
-		throw std::runtime_error("library not loaded");
-
-	sym = GetProcAddress(m_handle, name.c_str());
-	if (sym == nullptr)
-		throw std::out_of_range(systemError());
-
-	return sym;
-}
-
-void DynLib::systemClose()
-{
-	if (m_handle != nullptr)
-		FreeLibrary(m_handle);
-}
-
-#else
-
-void DynLib::systemInit()
-{
-	m_handle = nullptr;
-}
-
-DynLib::Handle DynLib::systemLoad(const std::string &path, Policy policy) const
-{
-	int mode = (policy == Immediately) ? RTLD_NOW : RTLD_LAZY;
-	Handle handle;
-
-	handle = dlopen(path.c_str(), mode);
-	if (handle == nullptr)
-		throw std::runtime_error(dlerror());
-
-	return handle;
-}
-
-DynLib::Sym DynLib::systemSym(const std::string &name)
-{
-	Sym sym;
-
-	if (m_handle == nullptr)
-		throw std::runtime_error("library not loaded");
-
-	sym = dlsym(m_handle, name.c_str());
-	if (sym == nullptr)
-		throw std::out_of_range(dlerror());
-
-	return sym;
-}
-
-void DynLib::systemClose()
-{
-	if (m_handle != nullptr)
-		dlclose(m_handle);
-}
-
-#endif
-
-DynLib::DynLib()
-{
-	systemInit();
-}
-
-DynLib::DynLib(const std::string &path, Policy policy)
-{
-	m_handle = systemLoad(path, policy);
-}
-
-DynLib::~DynLib()
-{
-	systemClose();
-}
--- a/C++/DynLib.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * DynLib.h -- portable shared library loader
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _DYN_LIB_H_
-#define _DYN_LIB_H_
-
-#include <string>
-
-#if defined(_WIN32)
-#  include <Windows.h>
-#  define DYNLIB_EXPORT	__declspec(dllexport)
-#else
-#  define DYNLIB_EXPORT
-#endif
-
-/**
- * @class DynLib
- * @brief Load a dynamic module
- *
- * This class is a portable wrapper to load shared libraries on
- * supported systems.
- */
-class DynLib {
-public:
-#if defined(_WIN32)
-	using Handle	= HMODULE;
-	using Sym	= FARPROC;
-#else
-	using Handle	= void *;
-	using Sym	= void *;
-#endif
-
-	enum Policy {
-		Immediately,		//! load symbols immediately
-		Lazy			//! load symbols when needed
-	};
-
-private:
-	Handle	m_handle;
-
-	void	systemInit();
-	Handle	systemLoad(const std::string &path, Policy policy) const;
-	Sym	systemSym(const std::string &name);
-	void	systemClose();
-
-public:
-	/**
-	 * Copy is forbidden.
-	 */
-	DynLib(const DynLib &) = delete;
-	DynLib &operator=(const DynLib &) = delete;
-
-	/**
-	 * Default constructor.
-	 */
-	DynLib();
-
-	/**
-	 * Constructor to load a shared module. The path must
-	 * be absolute.
-	 *
-	 * @param path the absolute path
-	 * @param policy the policy to load
-	 * @throw std::runtime_error on error
-	 */
-	DynLib(const std::string &path,
-	       Policy policy = Immediately);
-
-	/**
-	 * Close the library automatically.
-	 */
-	~DynLib();
-
-	/**
-	 * Get a symbol from the library.
-	 *
-	 * @param name the symbol
-	 * @return the symbol
-	 * @throw std::runtime_error on error
-	 * @throw std::out_of_range if not found
-	 */
-	template <typename T>
-	T sym(const std::string &name)
-	{
-		return reinterpret_cast<T>(systemSym(name));
-	}
-};
-
-#endif // !_DYN_LIB_H_
--- a/C++/Flags.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-/*
- * Flags.h -- safe wrapper for enum flags
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _FLAGS_H_
-#define _FLAGS_H_
-
-/**
- * @file Flags.h
- * @brief Provide template class Flags and operators for enum classes
- */
-
-#include <type_traits>
-
-/**
- * @class Flags
- * @brief Wrapper that store enum flags
- *
- * This class is used to store an enum and make bitwise operations on it. User do not need
- * to supply these operators because they are implemented in the class.
- *
- * This class is very cheap and store the real underlying type from the enum and all functions
- * are inlined.
- */
-template <typename Enum, typename Type = std::underlying_type_t<Enum>>
-class Flags final {
-private:
-	Type m_value { 0 };
-	
-public:
-	/**
-	 * Construct flags to 0.
-	 */
-	constexpr Flags() noexcept = default;
-
-	/**
-	 * Construct flags with the enum value.
-	 *
-	 * @param m the mask
-	 */
-	constexpr Flags(Enum m) noexcept
-		: m_value(static_cast<Type>(m))
-	{
-	}
-
-	/**
-	 * Construct flags with the enum value.
-	 *
-	 * @param m the mask
-	 */
-	constexpr Flags(Type m) noexcept
-		: m_value(m)
-	{
-	}
-
-	/**
-	 * Move constructor.
-	 *
-	 * @param other the other
-	 */
-	inline Flags(Flags &&other) noexcept = default;
-
-	/**
-	 * Copy constructor.
-	 *
-	 * @param other the other
-	 */
-	inline Flags(const Flags &other) noexcept = default;
-
-	/**
-	 * Move operator.
-	 *
-	 * @param other the other
-	 */
-	inline Flags &operator=(Flags &&other) noexcept = default;
-
-	/**
-	 * Copy operator.
-	 *
-	 * @param other the other
-	 */
-	inline Flags &operator=(const Flags &other) noexcept = default;
-
-	/**
-	 * &= operator.
-	 *
-	 * @param m the mask
-	 * @return *this
-	 */
-	inline Flags &operator&=(Enum m) noexcept
-	{
-		m_value &= static_cast<Type>(m);
-
-		return *this;
-	}
-	
-	/**
-	 * &= operator.
-	 *
-	 * @param m the mask
-	 * @return *this
-	 */
-	inline Flags &operator&=(Type m) noexcept
-	{
-		m_value &= m;
-
-		return *this;
-	}
-
-	/**
-	 * |= operator.
-	 *
-	 * @param m the mask
-	 * @return *this
-	 */
-	inline Flags &operator|=(Enum m) noexcept
-	{
-		m_value |= static_cast<Type>(m);
-
-		return *this;
-	}
-	
-	/**
-	 * |= operator.
-	 *
-	 * @param m the mask
-	 * @return *this
-	 */
-	inline Flags &operator|=(Type m) noexcept
-	{
-		m_value |= m;
-
-		return *this;
-	}
-
-	/**
-	 * ^= operator.
-	 *
-	 * @param m the mask
-	 * @return *this
-	 */
-	inline Flags &operator^=(Enum m) noexcept
-	{
-		m_value ^= static_cast<Type>(m);
-
-		return *this;
-	}
-	
-	/**
-	 * ^= operator.
-	 *
-	 * @param m the mask
-	 * @return *this
-	 */
-	inline Flags &operator^=(Type m) noexcept
-	{
-		m_value ^= m;
-
-		return *this;
-	}
-
-	/**
-	 * & operator.
-	 *
-	 * @param m the mask
-	 * @return & combination
-	 */
-	constexpr Flags operator&(Enum m) const noexcept
-	{
-		return m_value & static_cast<Type>(m);
-	}
-
-	/**
-	 * & operator.
-	 *
-	 * @param m the mask
-	 * @return & combination
-	 */
-	constexpr Flags operator&(Type m) const noexcept
-	{
-		return m_value & m;
-	}
-
-	/**
-	 * | operator.
-	 *
-	 * @param m the mask
-	 * @return | combination
-	 */
-	constexpr Flags operator|(Enum m) const noexcept
-	{
-		return m_value | static_cast<Type>(m);
-	}
-	
-	/**
-	 * | operator.
-	 *
-	 * @param m the mask
-	 * @return | combination
-	 */
-	constexpr Flags operator|(Type m) const noexcept
-	{
-		return m_value | m;
-	}
-
-	/**
-	 * ^ operator.
-	 *
-	 * @param m the mask
-	 * @return ^ combination
-	 */
-	constexpr Flags operator^(Enum m) const noexcept
-	{
-		return m_value & static_cast<Type>(m);
-	}
-
-	/**
-	 * ^ operator.
-	 *
-	 * @param m the mask
-	 * @return ^ combination
-	 */
-	constexpr Flags operator^(Type m) const noexcept
-	{
-		return m_value & m;
-	}
-
-	/**
-	 * ~ unary operator.
-	 *
-	 * @return ~
-	 */
-	constexpr Flags operator~() const noexcept
-	{
-		return ~m_value;
-	}
-
-	/**
-	 * Convert to bool. Simply check if value is not 0.
-	 *
-	 * @return true if value != 0
-	 */
-	constexpr operator bool() const noexcept
-	{
-		return m_value != 0;
-	}
-
-	/**
-	 * Operator !. Simply check if value is 0.
-	 *
-	 * @return true if value == 0
-	 */
-	constexpr bool operator!() const noexcept
-	{
-		return m_value == 0;
-	}
-
-	/**
-	 * Test comparison with other mask.
-	 *
-	 * @return true if this value == m
-	 */
-	constexpr bool operator==(Enum m) const noexcept
-	{
-		return m_value == static_cast<Type>(m);
-	}
-
-	/**
-	 * Test comparison with other mask.
-	 *
-	 * @return true if this value == m
-	 */
-	constexpr bool operator==(Type m) const noexcept
-	{
-		return m_value == m;
-	}
-};
-
-/**
- * Apply & operator on the enum.
- *
- * @param x1 the first value
- * @param x2 the second value
- */
-template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
-constexpr Value operator&(Value x1, Value x2) noexcept
-{
-	return static_cast<Value>(static_cast<Type>(x1) & static_cast<Type>(x2));
-}
-
-/**
- * Apply | operator on the enum.
- *
- * @param x1 the first value
- * @param x2 the second value
- */
-template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
-constexpr Value operator|(Value x1, Value x2) noexcept
-{
-	return static_cast<Value>(static_cast<Type>(x1) | static_cast<Type>(x2));
-}
-
-/**
- * Apply ^ operator on the enum.
- *
- * @param x1 the first value
- * @param x2 the second value
- */
-template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
-constexpr Value operator^(Value x1, Value x2) noexcept
-{
-	return static_cast<Value>(static_cast<Type>(x1) ^ static_cast<Type>(x2));
-}
-
-/**
- * Apply ~ operator on the enum.
- *
- * @param x1 the first value
- * @param x2 the second value
- */
-template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
-constexpr Value operator~(Value x) noexcept
-{
-	return static_cast<Value>(~static_cast<Type>(x));
-}
-
-#endif // !_FLAGS_H_
\ No newline at end of file
--- a/C++/Hash.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Hash.cpp -- hash functions
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "Hash.h"
-
-#include <openssl/sha.h>
-#include <openssl/md5.h>
-
-std::string Hash::md5(const std::string &input)
-{
-	return convert<MD5_CTX, MD5_DIGEST_LENGTH>(input, MD5_Init, MD5_Update, MD5_Final);
-}
-
-std::string Hash::sha1(const std::string &input)
-{
-	return convert<SHA_CTX, SHA_DIGEST_LENGTH>(input, SHA1_Init, SHA1_Update, SHA1_Final);
-}
-
-std::string Hash::sha256(const std::string &input)
-{
-	return convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(input, SHA256_Init, SHA256_Update, SHA256_Final);
-}
-
-std::string Hash::sha512(const std::string &input)
-{
-	return convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(input, SHA512_Init, SHA512_Update, SHA512_Final);
-}
--- a/C++/Hash.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Hash.h -- hash functions
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HASH_H_
-#define _HASH_H_
-
-/**
- * @file Hash.h
- * @brief Hash functions
- */
-
-#include <string>
-
-/**
- * @class Hash
- * @brief Hash functions
- *
- * Provide support for MD5, SHA1, SHA256 and SHA512.
- */
-class Hash {
-private:
-	template <typename Context>
-	using Init	= int (*)(Context *);
-
-	template <typename Context>
-	using Update	= int (*)(Context *, const void *, size_t);
-
-	template <typename Context>
-	using Final	= int (*)(unsigned char *, Context *);
-
-	template <typename Context, size_t Length>
-	static std::string convert(const std::string &input,
-				   Init<Context> init,
-				   Update<Context> update,
-				   Final<Context> finalize)
-	{
-		unsigned char digest[Length];
-		char hash[Length * 2 + 1];
-		
-		Context ctx;
-		init(&ctx);
-		update(&ctx, input.c_str(), input.length());
-		finalize(digest, &ctx);
-		
-		for (unsigned long i = 0; i < Length; i++)
-			sprintf(&hash[i * 2], "%02x", (unsigned int)digest[i]);
-		
-		return std::string(hash);
-	}
-
-public:
-	/**
-	 * Hash using MD5.
-	 *
-	 * @param input the input string
-	 * @return the hashed string
-	 */
-	static std::string md5(const std::string &input);
-
-	/**
-	 * Hash using SHA1.
-	 *
-	 * @param input the input string
-	 * @return the hashed string
-	 */
-	static std::string sha1(const std::string &input);
-
-	/**
-	 * Hash using SHA256.
-	 *
-	 * @param input the input string
-	 * @return the hashed string
-	 */
-	static std::string sha256(const std::string &input);
-
-	/**
-	 * Hash using SHA512.
-	 *
-	 * @param input the input string
-	 * @return the hashed string
-	 */
-	static std::string sha512(const std::string &input);
-};
-
-#endif // !_HASH_H_
--- a/C++/Ini.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,481 +0,0 @@
-/*
- * Ini.cpp -- .ini file parsing
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cctype>
-#include <cerrno>
-#include <cstring>
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <memory>
-#include <ostream>
-#include <sstream>
-#include <vector>
-
-#if defined(_WIN32)
-#  include <Shlwapi.h>	// for PathIsRelative
-#endif
-
-#include "Ini.h"
-
-namespace {
-
-/* --------------------------------------------------------
- * Tokens
- * -------------------------------------------------------- */
-
-enum class TokenType {
-	Comment = '#',
-	SectionBegin = '[',
-	SectionEnd = ']',
-	Escape = '\\',
-	QuoteSimple = '\'',
-	QuoteDouble = '"',
-	NewLine = '\n',
-	Assign = '=',
-	Include = '@',
-	Word,
-	Space
-};
-
-std::ostream &operator<<(std::ostream &out, const TokenType &type)
-{
-	switch (type) {
-	case TokenType::Comment:
-		out << "Comment";
-		break;
-	case TokenType::SectionBegin:
-		out << "SectionBegin";
-		break;
-	case TokenType::SectionEnd:
-		out << "SectionEnd";
-		break;
-	case TokenType::Escape:
-		out << "Escape";
-		break;
-	case TokenType::QuoteSimple:
-		out << "QuoteSimple";
-		break;
-	case TokenType::QuoteDouble:
-		out << "QuoteDouble";
-		break;
-	case TokenType::NewLine:
-		out << "NewLine";
-		break;
-	case TokenType::Assign:
-		out << "Assign";
-		break;
-	case TokenType::Include:
-		out << "Include";
-		break;
-	case TokenType::Word:
-		out << "Word";
-		break;
-	case TokenType::Space:
-		out << "Space";
-		break;
-	default:
-		break;
-	}
-
-	return out;
-}
-
-class Token {
-private:
-	TokenType m_type;
-	int m_line;
-	int m_position;
-	std::string m_value;
-
-public:
-	inline Token(TokenType type, int line, int position, std::string value = "")
-		: m_type(type)
-		, m_line(line)
-		, m_position(position)
-		, m_value(std::move(value))
-	{
-	}
-
-	inline TokenType type() const noexcept
-	{
-		return m_type;
-	}
-
-	inline int line() const noexcept
-	{
-		return m_line;
-	}
-
-	inline int position() const noexcept
-	{
-		return m_position;
-	}
-
-	inline std::string value() const
-	{
-		switch (m_type) {
-		case TokenType::Comment:
-			return "#";
-		case TokenType::SectionBegin:
-			return "[";
-		case TokenType::SectionEnd:
-			return "]";
-		case TokenType::QuoteSimple:
-			return "'";
-		case TokenType::QuoteDouble:
-			return "\"";
-		case TokenType::NewLine:
-			return "\n";
-		case TokenType::Assign:
-			return "=";
-		case TokenType::Include:
-			return "@";
-		case TokenType::Space:
-			return m_value;
-		case TokenType::Word:
-			return m_value;
-		default:
-			break;
-		}
-
-		return "";
-	}
-
-	inline std::string toString() const
-	{
-		switch (m_type) {
-		case TokenType::Comment:
-			return "'#'";
-		case TokenType::SectionBegin:
-			return "'['";
-		case TokenType::SectionEnd:
-			return "']'";
-		case TokenType::QuoteSimple:
-			return "'";
-		case TokenType::QuoteDouble:
-			return "\"";
-		case TokenType::NewLine:
-			return "<newline>";
-		case TokenType::Assign:
-			return "=";
-		case TokenType::Include:
-			return "@";
-		case TokenType::Space:
-			return "<blank>";
-		case TokenType::Word:
-			return "`" + m_value + "'";
-		default:
-			break;
-		}
-
-		return "";
-	}
-};
-
-std::ostream &operator<<(std::ostream &out, const Token &token)
-{
-	out << token.type();
-
-	if (token.type() == TokenType::Space) {
-		out << ": size = " << token.value().size();
-	} else if (token.type() == TokenType::Word) {
-		out << ": value = [" << token.value() << "]";
-	}
-
-	return out;
-}
-
-using TokenStack = std::vector<Token>;
-
-/* --------------------------------------------------------
- * IniBuilder
- * -------------------------------------------------------- */
-
-class IniBuilder {
-private:
-	std::string m_path;
-	std::string m_base;
-	Ini &m_ini;
-
-private:
-	inline bool isReserved(char c) const noexcept
-	{
-		return c == '\n' || c == '#' || c == '"' || c == '\'' || c == '=' || c == '[' || c == ']' || c == '@';
-	}
-
-	std::string base(std::string path)
-	{
-		auto pos = path.find_last_of("/\\");
-
-		if (pos != std::string::npos) {
-			path.erase(pos);
-		} else {
-			path = ".";
-		}
-
-		return path;
-	}
-
-#if defined(_WIN32)
-	bool isAbsolute(const std::string &path)
-	{
-		return !PathIsRelative(path.c_str());
-	}
-#else
-	bool isAbsolute(const std::string &path)
-	{
-		return path.size() > 0 && path[0] == '/';
-	}
-#endif
-
-	std::vector<Token> analyze(std::istream &stream) const
-	{
-		std::istreambuf_iterator<char> it(stream);
-		std::istreambuf_iterator<char> end;
-		std::vector<Token> tokens;
-
-		int lineno{1};
-		int position{0};
-
-		while (it != end) {
-			std::string value;
-
-			if (isReserved(*it)) {
-				while (it != end && isReserved(*it)) {
-					// Single character tokens
-					switch (*it) {
-					case '\n':
-						++lineno;
-						position = 0;
-					case '#':
-					case '[':
-					case ']':
-					case '\'':
-					case '"':
-					case '=':
-					case '@':
-						tokens.push_back({ static_cast<TokenType>(*it), lineno, position });
-						++it;
-						++position;
-					default:
-						break;
-					}
-				}
-			} else if (std::isspace(*it)) {
-				while (it != end && std::isspace(*it) && *it != '\n') {
-					value.push_back(*it++);
-				}
-
-				tokens.push_back({ TokenType::Space, lineno, position, std::move(value) });
-			} else {
-				while (it != end && !std::isspace(*it) && !isReserved(*it)) {
-					value.push_back(*it++);
-				}
-
-				tokens.push_back({ TokenType::Word, lineno, position, std::move(value) });
-			}
-		}
-
-		return tokens;
-	}
-
-	void readComment(TokenStack::iterator &it, TokenStack::iterator end)
-	{
-		while (it != end && it->type() != TokenType::NewLine) {
-			++ it;
-		}
-
-		// remove new line
-		++ it;
-	}
-
-	void readSpace(TokenStack::iterator &it, TokenStack::iterator end)
-	{
-		while (it != end && it->type() == TokenType::Space) {
-			++ it;
-		}
-	}
-
-	void readNewLine(TokenStack::iterator &it, TokenStack::iterator end)
-	{
-		while (it != end && it->type() == TokenType::NewLine) {
-			++ it;
-		}
-	}
-
-	IniSection readSection(TokenStack::iterator &it, TokenStack::iterator end)
-	{
-		if (++it == end || it->type() != TokenType::Word) {
-			throw IniError(it->line(), it->position(), "word expected after [, got " + it->toString());
-		}
-
-		IniSection section(it->value());
-
-		if (++it == end || it->type() != TokenType::SectionEnd) {
-			throw IniError(it->line(), it->position(), "] expected, got " + it->toString());
-		}
-
-		// Remove ]
-		++ it;
-
-		if (it == end) {
-			return section;
-		}
-
-		while (it != end && it->type() != TokenType::SectionBegin) {
-			if (it->type() == TokenType::Space) {
-				readSpace(it, end);
-			} else if (it->type() == TokenType::NewLine) {
-				readNewLine(it, end);
-			} else if (it->type() == TokenType::Comment) {
-				readComment(it, end);
-			} else if (it->type() == TokenType::Word) {
-				section.push_back(readOption(it, end));
-			} else {
-				throw IniError(it->line(), it->position(), "unexpected token " + it->toString());
-			}
-		}
-
-		return section;
-	}
-
-	IniOption readOption(TokenStack::iterator &it, TokenStack::iterator end)
-	{
-		std::string key = it->value();
-
-		if (++it == end) {
-			throw IniError(it->line(), it->position(), "expected '=' after option declaration, got <EOF>");
-		}
-
-		readSpace(it, end);
-
-		if (it == end || it->type() != TokenType::Assign) {
-			throw IniError(it->line(), it->position(), "expected '=' after option declaration, got " + it++->toString());
-		}
-
-		readSpace(++it, end);
-
-		std::ostringstream oss;
-
-		if (it->type() == TokenType::QuoteSimple || it->type() == TokenType::QuoteDouble) {
-			TokenStack::iterator save = it++;
-
-			while (it != end && it->type() != save->type()) {
-				oss << it++->value();
-			}
-
-			if (it == end)
-				throw IniError(save->line(), save->position(), "undisclosed quote: " + save->toString() + " expected");
-
-			++ it;
-		} else if (it->type() == TokenType::Word) {
-			oss << it++->value();
-		} else if (it->type() != TokenType::NewLine && it->type() != TokenType::Comment) {
-			// No value requested, must be NewLine or comment
-			throw IniError(it->line(), it->position(), "expected option value after '=', got " + it->toString());
-		}
-
-
-		return IniOption(std::move(key), oss.str());
-	}
-
-	void readInclude(TokenStack::iterator &it, TokenStack::iterator end)
-	{
-		if (++it == end || (it->type() != TokenType::Word || it->value() != "include")) {
-			throw IniError(it->line(), it->position(), "expected `include' after '@' token, got " + it->toString());
-		}
-
-		readSpace(++it, end);
-
-		// Quotes mandatory
-		TokenStack::iterator save = it;
-
-		if (it == end || (it->type() != TokenType::QuoteSimple && it->type() != TokenType::QuoteDouble)) {
-			throw IniError(it->line(), it->position(), "expected filename after @include statement");
-		}
-
-		// Filename
-		if (++it == end || it->type() != TokenType::Word) {
-			throw IniError(it->line(), it->position(), "expected filename after @include statement");
-		}
-
-		std::string value = it->value();
-		std::string fullpath;
-
-		if (isAbsolute(value)) {
-			fullpath = value;
-		} else {
-			fullpath = m_base + "/" + it->value();
-		}
-
-		// Must be closed with the same quote
-		if (++it == end || it->type() != save->type()) {
-			throw IniError(save->line(), save->position(), "undiclosed quote: " + save->toString() + " expected");
-		}
-
-		// Remove quote
-		++ it;
-
-		IniBuilder(m_ini, fullpath);
-	}
-
-public:
-	IniBuilder(Ini &ini, std::string path)
-		: m_path(path)
-		, m_base(base(std::move(path)))
-		, m_ini(ini)
-	{
-		std::ifstream file(m_path);
-
-		if (!file.is_open())
-			throw std::runtime_error(std::strerror(errno));
-
-		std::vector<Token> ts = analyze(file);
-
-		auto it = ts.begin();
-		auto end = ts.end();
-
-		while (it != end) {
-			if (it->type() == TokenType::Space) {
-				readSpace(it, end);
-			} else if (it->type() == TokenType::NewLine) {
-				readNewLine(it, end);
-			} else if (it->type() == TokenType::Comment) {
-				readComment(it, end);
-			} else if (it->type() == TokenType::Include) {
-				readInclude(it, end);
-			} else if (it->type() == TokenType::SectionBegin) {
-				m_ini.push_back(readSection(it, end));
-			} else {
-				throw IniError(it->line(), it->position(), "unexpected " + it->toString() + " on root document");
-			}
-		}
-	}
-};
-
-} // !namespace
-
-/* --------------------------------------------------------
- * Ini
- * -------------------------------------------------------- */
-
-Ini::Ini(const std::string &path)
-{
-	IniBuilder(*this, path);
-}
--- a/C++/Ini.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,494 +0,0 @@
-/*
- * Ini.h -- .ini file parsing
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _INI_H_
-#define _INI_H_
-
-/**
- * @file Ini.h
- * @brief Configuration file parser
- */
-
-#include <algorithm>
-#include <deque>
-#include <stdexcept>
-#include <string>
-
-/**
- * @class IniError
- * @brief Error in a file
- */
-class IniError : public std::exception {
-private:
-	int m_line;
-	int m_position;
-	std::string m_error;
-
-public:
-	/**
-	 * Construct an error.
-	 *
-	 * @param line the line
-	 * @param position the position
-	 * @param error the error
-	 */
-	inline IniError(int line, int position, std::string error)
-		: m_line(line)
-		, m_position(position)
-		, m_error(std::move(error))
-	{
-	}
-
-	/**
-	 * Return the line number.
-	 *
-	 * @return the line
-	 */
-	inline int line() const noexcept
-	{
-		return m_line;
-	}
-
-	/**
-	 * Return the position in the current line.
-	 *
-	 * @return the position
-	 */
-	inline int position() const noexcept
-	{
-		return m_position;
-	}
-
-	/**
-	 * Get the error string.
-	 *
-	 * @return the string
-	 */
-	inline const char *what() const noexcept
-	{
-		return m_error.c_str();
-	}
-};
-
-/**
- * @class IniOption
- * @brief Option definition
- */
-class IniOption {
-private:
-	std::string m_key;
-	std::string m_value;
-
-public:
-	/**
-	 * Construct an option.
-	 *
-	 * @param key the key
-	 * @param value the value
-	 */
-	inline IniOption(std::string key, std::string value)
-		: m_key(std::move(key))
-		, m_value(std::move(value))
-	{
-	}
-
-	/**
-	 * Get the option key.
-	 *
-	 * @return the key
-	 */
-	inline const std::string &key() const noexcept
-	{
-		return m_key;
-	}
-
-	/**
-	 * Get the option value.
-	 *
-	 * @return the value
-	 */
-	inline const std::string &value() const noexcept
-	{
-		return m_value;
-	}
-};
-
-/**
- * @class IniSection
- * @brief Section that contains one or more options
- */
-class IniSection {
-private:
-	std::string m_key;
-	std::deque<IniOption> m_options;
-
-	template <typename T>
-	T find(const std::string &key) const
-	{
-		auto it = std::find_if(m_options.begin(), m_options.end(), [&] (const IniOption &o) {
-			return o.key() == key;
-		});
-
-		if (it == m_options.end())
-			throw std::out_of_range("option " + key + " not found");
-
-		return const_cast<T>(*it);
-	}
-
-public:
-	/**
-	 * Default constructor has no sections and no values.
-	 */
-	IniSection() = default;
-
-	/**
-	 * Construct a section with a set of options.
-	 *
-	 * @param key the section name
-	 * @param options the list of options
-	 */
-	inline IniSection(std::string key, std::deque<IniOption> options = {}) noexcept
-		: m_key(std::move(key))
-		, m_options(std::move(options))
-	{
-	}
-
-	/**
-	 * Get the section key.
-	 *
-	 * @return the key
-	 */
-	inline const std::string &key() const noexcept
-	{
-		return m_key;
-	}
-
-	/**
-	 * Get an iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() noexcept
-	{
-		return m_options.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() const noexcept
-	{
-		return m_options.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cbegin() const noexcept
-	{
-		return m_options.cbegin();
-	}
-
-	/**
-	 * Get an iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() noexcept
-	{
-		return m_options.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() const noexcept
-	{
-		return m_options.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cend() const noexcept
-	{
-		return m_options.cend();
-	}
-
-	/**
-	 * Append an option.
-	 *
-	 * @param option the option to add
-	 */
-	inline void push_back(IniOption option)
-	{
-		m_options.push_back(std::move(option));
-	}
-
-	/**
-	 * Push an option to the beginning.
-	 *
-	 * @param option the option to add
-	 */
-	inline void push_front(IniOption option)
-	{
-		m_options.push_front(std::move(option));
-	}
-
-	/**
-	 * Get the number of options in that section.
-	 *
-	 * @return the size
-	 */
-	inline unsigned size() const noexcept
-	{
-		return m_options.size();
-	}
-
-	/**
-	 * Access an option at the specified index.
-	 *
-	 * @param index the index
-	 * @return the option
-	 * @warning No bounds checking is performed
-	 */
-	inline IniOption &operator[](int index) noexcept
-	{
-		return m_options[index];
-	}
-
-	/**
-	 * Access an option at the specified index.
-	 *
-	 * @param index the index
-	 * @return the option
-	 * @warning No bounds checking is performed
-	 */
-	inline const IniOption &operator[](int index) const noexcept
-	{
-		return m_options[index];
-	}
-
-	/**
-	 * Access an option at the specified key.
-	 *
-	 * @param key the key
-	 * @return the option
-	 * @warning No bounds checking is performed
-	 */
-	inline IniOption &operator[](const std::string &key)
-	{
-		return find<IniOption &>(key);
-	}
-
-	/**
-	 * Access an option at the specified key.
-	 *
-	 * @param key the key
-	 * @return the option
-	 * @warning No bounds checking is performed
-	 */
-	inline const IniOption &operator[](const std::string &key) const
-	{
-		return find<const IniOption &>(key);
-	}
-};
-
-/**
- * @class Ini
- * @brief Ini config file loader
- */
-class Ini {
-private:
-	std::deque<IniSection> m_sections;
-
-	template <typename T>
-	T find(const std::string &key) const
-	{
-		auto it = std::find_if(m_sections.begin(), m_sections.end(), [&] (const IniSection &s) {
-			return s.key() == key;
-		});
-
-		if (it == m_sections.end())
-			throw std::out_of_range("section " + key + " not found");
-
-		return const_cast<T>(*it);
-	}
-
-public:
-	/**
-	 * Default constructor with an empty configuration.
-	 */
-	Ini() = default;
-
-	/**
-	 * Open the path as the configuration file.
-	 *
-	 * @param path the path
-	 * @throw IniError on any error
-	 */
-	Ini(const std::string &path);
-
-	/**
-	 * Get an iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() noexcept
-	{
-		return m_sections.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() const noexcept
-	{
-		return m_sections.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cbegin() const noexcept
-	{
-		return m_sections.cbegin();
-	}
-
-	/**
-	 * Get an iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() noexcept
-	{
-		return m_sections.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() const noexcept
-	{
-		return m_sections.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cend() const noexcept
-	{
-		return m_sections.cend();
-	}
-
-	/**
-	 * Get the number of sections in the configuration.
-	 *
-	 * @return the size
-	 */
-	inline unsigned size() const noexcept
-	{
-		return m_sections.size();
-	}
-
-	/**
-	 * Append a section to the end.
-	 *
-	 * @param section the section to add
-	 */
-	inline void push_back(IniSection section)
-	{
-		m_sections.push_back(std::move(section));
-	}
-
-	/**
-	 * Add a section to the beginning.
-	 *
-	 * @param section the section to add
-	 */
-	inline void push_front(IniSection section)
-	{
-		m_sections.push_front(std::move(section));
-	}
-
-	/**
-	 * Access a section at the specified index.
-	 *
-	 * @param index the index
-	 * @return the section
-	 * @warning No bounds checking is performed
-	 */
-	inline IniSection &operator[](int index) noexcept
-	{
-		return m_sections[index];
-	}
-
-	/**
-	 * Access a section at the specified index.
-	 *
-	 * @param index the index
-	 * @return the section
-	 * @warning No bounds checking is performed
-	 */
-	inline const IniSection &operator[](int index) const noexcept
-	{
-		return m_sections[index];
-	}
-
-	/**
-	 * Access a section at the specified key.
-	 *
-	 * @param key the key
-	 * @return the section
-	 * @warning No bounds checking is performed
-	 */
-	inline IniSection &operator[](const std::string &key)
-	{
-		return find<IniSection &>(key);
-	}
-
-	/**
-	 * Access a section at the specified key.
-	 *
-	 * @param key the key
-	 * @return the section
-	 * @warning No bounds checking is performed
-	 */
-	inline const IniSection &operator[](const std::string &key) const
-	{
-		return find<IniSection &>(key);
-	}
-};
-
-#endif // !_INI_H_
--- a/C++/Json.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Json.cpp -- jansson C++11 wrapper
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdexcept>
-
-#include "Json.h"
-
-/* --------------------------------------------------------
- * JsonObject
- * -------------------------------------------------------- */
-
-JsonObject JsonValue::toObject() const noexcept
-{
-	json_incref(m_handle.get());
-
-	return JsonObject(m_handle.get());
-}
-
-JsonArray JsonValue::toArray() const noexcept
-{
-	json_incref(m_handle.get());
-
-	return JsonArray(m_handle.get());
-}
-
-/* --------------------------------------------------------
- * JsonArray
- * -------------------------------------------------------- */
-
-JsonValue JsonArray::at(int index) const
-{
-	auto value = json_array_get(m_handle.get(), index);
-
-	if (value == nullptr)
-		throw JsonError("index out of bounds");
-
-	json_incref(value);
-
-	return JsonValue{value};
-}
-
-JsonValue JsonArray::operator[](int index) const noexcept
-{
-	auto value = json_array_get(m_handle.get(), index);
-
-	if (value == nullptr)
-		return JsonValue();
-
-	json_incref(value);
-
-	return JsonValue(value);
-}
-
-JsonArray::Ref JsonArray::operator[](int index) noexcept
-{
-	auto value = json_array_get(m_handle.get(), index);
-
-	if (value == nullptr)
-		value = json_null();
-	else
-		json_incref(value);
-
-	return Ref(value, *this, index);
-}
-
-/* --------------------------------------------------------
- * JsonObject
- * -------------------------------------------------------- */
-
-JsonObject::Ref JsonObject::operator[](const std::string &name)
-{
-	if (typeOf() != JsonType::Object)
-		return Ref(JsonValue(), *this, name);
-
-	auto value = json_object_get(m_handle.get(), name.c_str());
-
-	json_incref(value);
-
-	return Ref(value, *this, name);
-}
-
-JsonValue JsonObject::operator[](const std::string &name) const
-{
-	if (typeOf() != JsonType::Object)
-		return JsonValue();
-
-	auto value = json_object_get(m_handle.get(), name.c_str());
-
-	if (value == nullptr)
-		return JsonValue();
-
-	json_incref(value);
-
-	return JsonValue(value);
-}
-
-/* --------------------------------------------------------
- * JsonDocument
- * -------------------------------------------------------- */
-
-JsonValue JsonDocument::read(std::string content, int flags) const
-{
-	json_error_t error;
-	json_t *json = json_loads(content.c_str(), flags, &error);
-
-	if (json == nullptr)
-		throw JsonError(error);
-
-	return JsonValue(json);
-}
-
-JsonValue JsonDocument::read(std::ifstream &stream, int flags) const
-{
-	if (!stream.is_open())
-		throw JsonError("File not opened");
-
-	stream.seekg(0, stream.end);
-	auto length = stream.tellg();
-	stream.seekg(0, stream.beg);
-
-	std::string buffer;
-	buffer.resize(length, ' ');
-
-	stream.read(&buffer[0], length);
-	stream.close();
-
-	return read(std::move(buffer), flags);
-}
-
-JsonDocument::JsonDocument(std::ifstream &stream, int flags)
-{
-	m_value = read(stream, flags);
-}
-
-JsonDocument::JsonDocument(std::ifstream &&stream, int flags)
-{
-	m_value = read(stream, flags);
-}
-
-JsonDocument::JsonDocument(std::string content, int flags)
-{
-	m_value = read(std::move(content), flags);
-}
\ No newline at end of file
--- a/C++/Json.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1603 +0,0 @@
-/*
- * Json.h -- jansson C++11 wrapper
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _JSON_H_
-#define _JSON_H_
-
-#include <algorithm>
-#include <cerrno>
-#include <cstdlib>
-#include <cstring>
-#include <initializer_list>
-#include <fstream>
-#include <iterator>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <jansson.h>
-
-/**
- * @file Json.h
- * @brief A jansson C++ modern wrapper
- *
- * Because of the Jansson implementation, all these classes are implicitly
- * shared.
- *
- * This means that you can't set any value to an existing value as it would
- * change a value which may be used somewhere else, instead you must set
- * or replace elements in JsonObject and JsonArray respectively.
- *
- * However, copy constructors are implemented as deep copy so take care of
- * not copying values mistakenly.
- */
-
-/**
- * @class JsonType
- * @brief Json value type
- */
-enum class JsonType {
-	Object = JSON_OBJECT,		//!< Object
-	Array = JSON_ARRAY,		//!< Array
-	String = JSON_STRING,		//!< String
-	Integer = JSON_INTEGER,		//!< Integer
-	Real = JSON_REAL,		//!< Floating point
-	True = JSON_TRUE,		//!< Boolean true
-	False = JSON_FALSE,		//!< Boolean false
-	Null = JSON_NULL		//!< Empty or null
-};
-
-/**
- * @class JsonError
- * @brief Error thrown for any error
- */
-class JsonError final : public std::exception {
-private:
-	std::string	m_text;
-	std::string	m_source;
-	int		m_line{};
-	int		m_column{};
-	int		m_position{};
-
-public:
-	/**
-	 * Custom error with no line, no column and no position.
-	 *
-	 * @param error the error message
-	 */
-	inline JsonError(std::string error)
-		: m_text(std::move(error))
-	{
-	}
-
-	/**
-	 * Error from a json_error_t.
-	 *
-	 * @param error the error
-	 */
-	inline JsonError(const json_error_t &error)
-		: m_text(error.text)
-		, m_source(error.source)
-		, m_line(error.line)
-		, m_column(error.column)
-		, m_position(error.position)
-	{
-	}
-
-	/**
-	 * Get the error message.
-	 *
-	 * @return the message
-	 */
-	const char *what() const noexcept override
-	{
-		return m_text.c_str();
-	}
-
-	/**
-	 * Get the text message.
-	 *
-	 * @return the text
-	 */
-	inline const std::string &text() const noexcept
-	{
-		return m_text;
-	}
-
-	/**
-	 * Get the source.
-	 *
-	 * @return the source
-	 */
-	inline const std::string &source() const noexcept
-	{
-		return m_source;
-	}
-
-	/**
-	 * Get the line.
-	 *
-	 * @return the line
-	 */
-	inline int line() const noexcept
-	{
-		return m_line;
-	}
-
-	/**
-	 * Get the column.
-	 *
-	 * @return the column
-	 */
-	inline int column() const noexcept
-	{
-		return m_column;
-	}
-
-	/**
-	 * Get the position.
-	 *
-	 * @return the position
-	 */
-	inline int position() const noexcept
-	{
-		return m_position;
-	}
-};
-
-class JsonObject;
-class JsonArray;
-
-/**
- * @class JsonValue
- * @brief Encapsulate any JSON value
- */
-class JsonValue {
-public:
-	using Handle = std::unique_ptr<json_t, void (*)(json_t *)>;
-
-	friend class JsonObject;
-	friend class JsonArray;
-
-protected:
-	/**
-	 * The unique_ptr handle of json_t, will automatically decrease
-	 * the reference count in its deleter.
-	 */
-	Handle m_handle;
-
-	inline void check() const
-	{
-		if (m_handle == nullptr)
-			throw JsonError(std::strerror(errno));
-	}
-
-public:
-	/**
-	 * Deep copy of that element.
-	 *
-	 * @param value the other value
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonValue(const JsonValue &value)
-		: m_handle(json_deep_copy(value.m_handle.get()), json_decref)
-	{
-		check();
-	}
-
-	/**
-	 * Assign a deep copy of the other element.
-	 *
-	 * @return *this
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonValue &operator=(const JsonValue &value)
-	{
-		m_handle = Handle(json_deep_copy(value.m_handle.get()), json_decref);
-
-		check();
-
-		return *this;
-	}
-
-	/**
-	 * Move constructor, the other value is left empty (JsonType::Null).
-	 *
-	 * @param other the other value
-	 */
-	inline JsonValue(JsonValue &&other) noexcept
-		: m_handle(std::move(other.m_handle))
-	{
-		other.m_handle = Handle(json_null(), json_decref);
-	}
-
-	/**
-	 * Move assignment, the other value is left empty (JsonType::Null).
-	 *
-	 * @param other the other value
-	 */
-	inline JsonValue &operator=(JsonValue &&other) noexcept
-	{
-		m_handle = std::move(other.m_handle);
-		other.m_handle = Handle(json_null(), json_decref);
-
-		return *this;
-	}
-
-	/**
-	 * Create a JsonValue from a native Jansson type. This function
-	 * will increment the json_t reference count.
-	 *
-	 * @param json the value
-	 */
-	inline JsonValue(json_t *json) noexcept
-		: m_handle(json, json_decref)
-	{
-	}
-
-	/**
-	 * Construct a null value from a nullptr argument.
-	 */
-	inline JsonValue(std::nullptr_t) noexcept
-		: m_handle(json_null(), json_decref)
-	{
-	}
-
-	/**
-	 * Create an empty value (JsonType::Null).
-	 */
-	inline JsonValue() noexcept
-		: m_handle(json_null(), json_decref)
-	{
-	}
-
-	/**
-	 * Create a boolean value.
-	 *
-	 * @param value the value
-	 */
-	inline JsonValue(bool value) noexcept
-		: m_handle(json_boolean(value), json_decref)
-	{
-	}
-
-	/**
-	 * Create a integer value (JsonType::Integer).
-	 *
-	 * @param value the value
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonValue(int value)
-		: m_handle(json_integer(value), json_decref)
-	{
-		check();
-	}
-
-	/**
-	 * Create a real value (JsonType::Real).
-	 *
-	 * @param value the value
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonValue(double value)
-		: m_handle(json_real(value), json_decref)
-	{
-		check();
-	}
-
-	/**
-	 * Create a string value (JsonType::String).
-	 *
-	 * @param value the value
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonValue(std::string value)
-		: m_handle(json_string(value.c_str()), json_decref)
-	{
-		check();
-	}
-
-	/**
-	 * Create from a C string (JsonType::String).
-	 *
-	 * @param value the string
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonValue(const char *value)
-		: m_handle(json_string(value), json_decref)
-	{
-		check();
-	}
-
-	/**
-	 * Create from a string literal (JsonType::String).
-	 *
-	 * @param value the value
-	 * @throw JsonError on allocation error
-	 */
-	template <size_t Size>
-	inline JsonValue(char (&value)[Size])
-		: m_handle(json_string(value), json_decref)
-	{
-		check();
-	}
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~JsonValue() = default;
-
-	/**
-	 * Get the type of value.
-	 *
-	 * @return the type
-	 */
-	inline JsonType typeOf() const noexcept
-	{
-		return static_cast<JsonType>(json_typeof(m_handle.get()));
-	}
-
-	/**
-	 * Tells if the json value is an JSON_OBJECT.
-	 *
-	 * @return true or false
-	 */
-	inline bool isObject() const noexcept
-	{
-		return json_is_object(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_ARRAY.
-	 *
-	 * @return true or false
-	 */
-	inline bool isArray() const noexcept
-	{
-		return json_is_array(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_STRING.
-	 *
-	 * @return true or false
-	 */
-	inline bool isString() const noexcept
-	{
-		return json_is_string(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_REAL.
-	 *
-	 * @return true or false
-	 */
-	inline bool isReal() const noexcept
-	{
-		return json_is_real(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_TRUE.
-	 *
-	 * @return true or false
-	 */
-	inline bool isTrue() const noexcept
-	{
-		return json_is_true(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_FALSE.
-	 *
-	 * @return true or false
-	 */
-	inline bool isFalse() const noexcept
-	{
-		return json_is_false(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_NULL.
-	 *
-	 * @return true or false
-	 */
-	inline bool isNull() const noexcept
-	{
-		return json_is_null(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_INTEGER or JSON_REAL.
-	 *
-	 * @return true or false
-	 */
-	inline bool isNumber() const noexcept
-	{
-		return json_is_number(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_INTEGER.
-	 *
-	 * @return true or false
-	 */
-	inline bool isInteger() const noexcept
-	{
-		return json_is_integer(m_handle.get());
-	}
-
-	/**
-	 * Tells if the json value is an JSON_TRUE or JSON_FALSE.
-	 *
-	 * @return true or false
-	 */
-	inline bool isBoolean() const noexcept
-	{
-		return json_is_boolean(m_handle.get());
-	}
-
-	/**
-	 * Get the string value.
-	 *
-	 * @return the string
-	 */
-	inline std::string toString() const noexcept
-	{
-		auto value = json_string_value(m_handle.get());
-
-		return (value == nullptr) ? "" : value;
-	}
-
-	/**
-	 * Get the integer value.
-	 *
-	 * @return the value or 0
-	 */
-	inline int toInteger() const noexcept
-	{
-		return json_integer_value(m_handle.get());
-	}
-
-	/**
-	 * Get the real value.
-	 *
-	 * @return the value or 0
-	 */
-	inline double toReal() const noexcept
-	{
-		return json_real_value(m_handle.get());
-	}
-
-	/**
-	 * Convert to object.
-	 *
-	 * @return an object
-	 */
-	JsonObject toObject() const noexcept;
-
-	/**
-	 * Convert to array.
-	 *
-	 * @return an array
-	 */
-	JsonArray toArray() const noexcept;
-
-	/**
-	 * Write to a stream.
-	 *
-	 * @param out the out
-	 * @param flags the optional Jansson flags
-	 */
-	inline void write(std::ofstream &out, int flags = 0) const
-	{
-		auto content = dump(flags);
-
-		std::copy(std::begin(content), std::end(content), std::ostreambuf_iterator<char>(out));
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param out the out
-	 * @param flags the optional Jansson flags
-	 */
-	inline void write(std::ofstream &&out, int flags = 0) const
-	{
-		write(out, flags);
-	}
-
-	/**
-	 * Convert the Json value as a string.
-	 *
-	 * @return the string
-	 * @param flags the optional Jansson flags
-	 */
-	inline std::string dump(int flags = 0) const
-	{
-		auto str = json_dumps(m_handle.get(), flags);
-
-		if (str == nullptr)
-			return "";
-
-		std::string ret(str);
-		std::free(str);
-
-		return ret;
-	}
-
-	/**
-	 * Convert to native Jansson type.
-	 *
-	 * You should not call json_incref or json_decref on it as it is
-	 * automatically done.
-	 *
-	 * @return the json_t handle
-	 * @warning use this function with care
-	 */
-	inline operator json_t *() noexcept
-	{
-		return m_handle.get();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the json_t handle
-	 */
-	inline operator const json_t *() const noexcept
-	{
-		return m_handle.get();
-	}
-
-	/**
-	 * Equality operator.
-	 */
-	inline bool operator==(const JsonValue &other) const noexcept
-	{
-		return json_equal(m_handle.get(), other.m_handle.get());
-	}
-};
-
-/**
- * @class JsonArray
- * @brief Manipulate JSON arrays
- */
-class JsonArray final : public JsonValue {
-public:
-	/**
-	 * @class Ref
-	 * @brief Reference wrapper to be assignable
-	 */
-	class Ref final : public JsonValue {
-	private:
-		JsonArray &m_array;
-		int m_index;
-
-	public:
-		explicit inline Ref(JsonValue value, JsonArray &array, int index)
-			: JsonValue(std::move(value))
-			, m_array(array)
-			, m_index(index)
-		{
-		}
-
-		inline operator JsonValue() const noexcept
-		{
-			return *this;
-		}
-
-		inline JsonValue &operator*() noexcept
-		{
-			return *this;
-		}
-
-		inline JsonValue *operator->() noexcept
-		{
-			return this;
-		}
-
-		inline Ref &operator=(const JsonValue &value)
-		{
-			m_array.replace(value, m_index);
-
-			return *this;
-		}
-
-		inline Ref &operator=(JsonValue &&value)
-		{
-			m_array.replace(std::move(value), m_index);
-
-			return *this;
-		}
-	};
-
-	/**
-	 * @class Ptr
-	 * @brief Pointer wrapper for JsonValue iterators
-	 */
-	class Ptr final : public JsonValue {
-	public:
-		explicit Ptr(JsonValue value) noexcept
-			: JsonValue(std::move(value))
-		{
-		}
-
-		inline JsonValue &operator*() noexcept
-		{
-			return *this;
-		}
-
-		inline JsonValue *operator->() noexcept
-		{
-			return this;
-		}
-	};
-
-	class iterator final {
-	public:
-		using iterator_category = std::random_access_iterator_tag;
-		using difference_type = int;
-		using value_type = JsonValue;
-		using reference = Ref;
-		using pointer = Ptr;
-
-		friend class JsonArray;
-
-	private:
-		JsonArray &m_array;
-		int m_index;
-
-	public:
-		explicit inline iterator(JsonArray &array, int index = 0) noexcept
-			: m_array(array)
-			, m_index(index)
-		{
-		}
-
-		inline Ref operator*() const
-		{
-			return Ref(m_array.at(m_index), m_array, m_index);
-		}
-
-		inline Ptr operator->() const
-		{
-			return Ptr(m_array.at(m_index));
-		}
-
-		inline Ref operator[](int nindex) const noexcept
-		{
-			return Ref(m_array.at(m_index + nindex), m_array, m_index + nindex);
-		}
-
-		inline bool operator==(const iterator &other) const noexcept
-		{
-			return m_index == other.m_index;
-		}
-
-		inline bool operator!=(const iterator &other) const noexcept
-		{
-			return m_index != other.m_index;
-		}
-
-		inline bool operator<(const iterator &other) const noexcept
-		{
-			return m_index < other.m_index;
-		}
-
-		inline bool operator<=(const iterator &other) const noexcept
-		{
-			return m_index <= other.m_index;
-		}
-
-		inline bool operator>(const iterator &other) const noexcept
-		{
-			return m_index > other.m_index;
-		}
-
-		inline bool operator>=(const iterator &other) const noexcept
-		{
-			return m_index >= other.m_index;
-		}
-
-		inline iterator &operator++() noexcept
-		{
-			++m_index;
-
-			return *this;
-		}
-
-		inline iterator operator++(int) noexcept
-		{
-			iterator save = *this;
-
-			++m_index;
-
-			return save;
-		}
-
-		inline iterator &operator--() noexcept
-		{
-			m_index--;
-
-			return *this;
-		}
-
-		inline iterator operator--(int) noexcept
-		{
-			iterator save = *this;
-
-			m_index--;
-
-			return save;
-		}
-
-		inline iterator &operator+=(int nindex) noexcept
-		{
-			m_index += nindex;
-
-			return *this;
-		}
-
-		inline iterator &operator-=(int nindex) noexcept
-		{
-			m_index -= nindex;
-
-			return *this;
-		}
-
-		inline iterator operator+(int nindex) const noexcept
-		{
-			return iterator(m_array, m_index + nindex);
-		}
-
-		inline iterator operator-(int nindex) const noexcept
-		{
-			return iterator(m_array, m_index - nindex);
-		}
-
-		inline int operator-(iterator other) const noexcept
-		{
-			return m_index - other.m_index;
-		}
-	};
-
-	class const_iterator final {
-	public:
-		using iterator_category = std::random_access_iterator_tag;
-		using difference_type = int;
-		using value_type = JsonValue;
-		using reference = JsonValue;
-		using pointer = Ptr;
-
-		friend class JsonArray;
-
-	private:
-		const JsonArray &m_array;
-		int m_index;
-
-	public:
-		explicit inline const_iterator(const JsonArray &array, int index = 0) noexcept
-			: m_array(array)
-			, m_index(index)
-		{
-		}
-
-		inline JsonValue operator*() const
-		{
-			return m_array.at(m_index);
-		}
-
-		inline Ptr operator->() const
-		{
-			return Ptr(m_array.at(m_index));
-		}
-
-		inline JsonValue operator[](int nindex) const noexcept
-		{
-			return m_array.at(m_index + nindex);
-		}
-
-		inline bool operator==(const const_iterator &other) const noexcept
-		{
-			return m_index == other.m_index;
-		}
-
-		inline bool operator!=(const const_iterator &other) const noexcept
-		{
-			return m_index != other.m_index;
-		}
-
-		inline bool operator<(const const_iterator &other) const noexcept
-		{
-			return m_index < other.m_index;
-		}
-
-		inline bool operator<=(const const_iterator &other) const noexcept
-		{
-			return m_index <= other.m_index;
-		}
-
-		inline bool operator>(const const_iterator &other) const noexcept
-		{
-			return m_index > other.m_index;
-		}
-
-		inline bool operator>=(const const_iterator &other) const noexcept
-		{
-			return m_index >= other.m_index;
-		}
-
-		inline const_iterator &operator++() noexcept
-		{
-			++m_index;
-
-			return *this;
-		}
-
-		inline const_iterator operator++(int) noexcept
-		{
-			const_iterator save = *this;
-
-			++m_index;
-
-			return save;
-		}
-
-		inline const_iterator &operator--() noexcept
-		{
-			m_index--;
-
-			return *this;
-		}
-
-		inline const_iterator operator--(int) noexcept
-		{
-			const_iterator save = *this;
-
-			m_index--;
-
-			return save;
-		}
-
-		inline const_iterator &operator+=(int nindex) noexcept
-		{
-			m_index += nindex;
-
-			return *this;
-		}
-
-		inline const_iterator &operator-=(int nindex) noexcept
-		{
-			m_index -= nindex;
-
-			return *this;
-		}
-
-		inline const_iterator operator+(int nindex) const noexcept
-		{
-			return const_iterator(m_array, m_index + nindex);
-		}
-
-		inline const_iterator operator-(int nindex) const noexcept
-		{
-			return const_iterator(m_array, m_index - nindex);
-		}
-
-		inline int operator-(const_iterator other) const noexcept
-		{
-			return m_index - other.m_index;
-		}
-	};
-
-	using size_type = int;
-	using value_type = JsonValue;
-	using const_pointer = const value_type *;
-	using reference = JsonValue &;
-	using const_reference = const JsonValue &;
-	using difference_type = int;
-
-protected:
-	using JsonValue::JsonValue;
-
-public:
-	/**
-	 * Create an empty array.
-	 *
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonArray()
-		: JsonValue(json_array())
-	{
-		check();
-	}
-
-	/**
-	 * Create an array from a list of values.
-	 *
-	 * @param list the list
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonArray(std::initializer_list<value_type> list)
-		: JsonArray()
-	{
-		for (auto &v : list)
-			append(std::move(v));
-	}
-
-	/**
-	 * Returns an iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline iterator begin() noexcept
-	{
-		return iterator(*this, 0);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator begin() const noexcept
-	{
-		return const_iterator(*this, 0);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator cbegin() const noexcept
-	{
-		return const_iterator(*this, 0);
-	}
-
-	/**
-	 * Returns an iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline iterator end() noexcept
-	{
-		return iterator(*this, size());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator end() const noexcept
-	{
-		return const_iterator(*this, size());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator cend() const noexcept
-	{
-		return const_iterator(*this, size());
-	}
-
-	/**
-	 * Get a value.
-	 *
-	 * @param index the index
-	 * @throw JsonError on error
-	 */
-	JsonValue at(int index) const;
-
-	/**
-	 * Erase the array content.
-	 */
-	inline void clear() noexcept
-	{
-		json_array_clear(m_handle.get());
-	}
-
-	/**
-	 * Remove the element at the specified index.
-	 *
-	 * @param index the index
-	 */
-	inline void erase(int index) noexcept
-	{
-		json_array_remove(m_handle.get(), index);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param it the iterator
-	 */
-	inline void erase(iterator it) noexcept
-	{
-		erase(it.m_index);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param it the iterator
-	 */
-	inline void erase(const_iterator it) noexcept
-	{
-		erase(it.m_index);
-	}
-
-	/**
-	 * Get the number of values in the array
-	 *
-	 * @return the number or 0
-	 */
-	inline unsigned size() const noexcept
-	{
-		return json_array_size(m_handle.get());
-	}
-
-	/**
-	 * Insert the value at the beginning.
-	 *
-	 * @param value the value
-	 */
-	inline void push(const JsonValue &value) noexcept
-	{
-		json_array_insert(m_handle.get(), 0, value.m_handle.get());
-	}
-
-	/**
-	 * Insert a copy of the value at the end.
-	 *
-	 * @param value the value to insert
-	 */
-	inline void append(const JsonValue &value)
-	{
-		json_array_append(m_handle.get(), value.m_handle.get());
-	}
-
-	/**
-	 * Insert a copy of the value at the specified index.
-	 *
-	 * @param value the value to insert
-	 * @param index the position
-	 */
-	inline void insert(const JsonValue &value, int index)
-	{
-		json_array_insert(m_handle.get(), index, value.m_handle.get());
-	}
-
-	/**
-	 * Replace the value at the given index.
-	 *
-	 * @param value the value
-	 * @param index the index
-	 */
-	inline void replace(const JsonValue &value, int index)
-	{
-		json_array_set(m_handle.get(), index, value.m_handle.get());
-	}
-
-	/**
-	 * Get the value at the specified index.
-	 *
-	 * @param index the position
-	 * @return the value
-	 */
-	JsonValue operator[](int index) const noexcept;
-
-	/**
-	 * Access a value as a reference wrapper.
-	 *
-	 * @param index the position
-	 * @return the reference wrapper over the value
-	 */
-	Ref operator[](int index) noexcept;
-};
-
-/**
- * @class JsonObject
- * @brief Object wrapper
- */
-class JsonObject final : public JsonValue {
-public:
-	using key_type = std::string;
-	using mapped_type = JsonValue;
-	using size_type = int;
-	using value_type = std::pair<key_type, mapped_type>;
-	using const_pointer = const value_type *;
-	using reference = JsonValue &;
-	using const_reference = const JsonValue &;
-	using difference_type = int;
-
-	/**
-	 * @class Ref
-	 * @brief Wrapper for updating JsonObject
-	 *
-	 * This class is only used for the following functions:
-	 *
-	 *	JsonObject::operator[]
-	 */
-	class Ref final : public JsonValue {
-	private:
-		JsonObject &m_object;
-		std::string m_key;
-
-	public:
-		explicit inline Ref(JsonValue value, JsonObject &object, std::string key)
-			: JsonValue(std::move(value))
-			, m_object(object)
-			, m_key(std::move(key))
-		{
-		}
-
-		inline operator JsonValue() const noexcept
-		{
-			return *this;
-		}
-
-		inline JsonValue &operator*() noexcept
-		{
-			return *this;
-		}
-
-		inline JsonValue *operator->() noexcept
-		{
-			return this;
-		}
-
-		inline Ref &operator=(const JsonValue &value)
-		{
-			m_object.set(m_key, value);
-
-			return *this;
-		}
-
-		inline Ref &operator=(JsonValue &&value)
-		{
-			m_object.set(m_key, std::move(value));
-
-			return *this;
-		}
-	};
-
-	/**
-	 * @class Ptr
-	 * @brief Pointer wrapper for JsonValue iterators
-	 *
-	 * For const iterators, the real type is a JsonValue, for non const
-	 * iterators it's a ref so that user can edit it.
-	 */
-	template <typename Type>
-	class Ptr final {
-	private:
-		std::pair<std::string, Type> m_pair;
-
-	public:
-		inline Ptr(std::pair<std::string, Type> value) noexcept
-			: m_pair(std::move(value))
-		{
-		}
-
-		inline std::pair<std::string, Type> &operator*() noexcept
-		{
-			return m_pair;
-		}
-
-		inline std::pair<std::string, Type> *operator->() noexcept
-		{
-			return &m_pair;
-		}
-	};
-
-	/**
-	 * @class iterator
-	 * @brief Forward iterator
-	 */
-	class iterator {
-	public:
-		using value_type = std::pair<std::string, Ref>;
-
-		friend class JsonObject;
-
-	private:
-		JsonObject &m_object;
-		void *m_keyIt;
-
-		inline std::string key() const noexcept
-		{
-			return json_object_iter_key(m_keyIt);
-		}
-
-	public:
-		explicit inline iterator(JsonObject &object, void *keyIt) noexcept
-			: m_object(object)
-			, m_keyIt(keyIt)
-		{
-		}
-
-		inline value_type operator*() const
-		{
-			auto k = key();
-
-			return value_type(k, Ref(m_object[k], m_object, k));
-		}
-
-		inline Ptr<Ref> operator->() const
-		{
-			auto k = key();
-
-			return Ptr<Ref>({k, Ref(m_object[k], m_object, k)});
-		}
-
-		inline iterator &operator++() noexcept
-		{
-			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
-
-			return *this;
-		}
-
-		inline iterator operator++(int) noexcept
-		{
-			iterator save = *this;
-
-			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
-
-			return save;
-		}
-
-		inline bool operator==(iterator other) const noexcept
-		{
-			return m_keyIt == other.m_keyIt;
-		}
-
-		inline bool operator!=(iterator other) const noexcept
-		{
-			return m_keyIt != other.m_keyIt;
-		}
-	};
-
-	/**
-	 * @class const_iterator
-	 * @brief Forward iterator
-	 */
-	class const_iterator {
-	public:
-		using value_type = std::pair<std::string, JsonValue>;
-
-		friend class JsonObject;
-
-	private:
-		const JsonObject &m_object;
-		void *m_keyIt;
-
-		inline std::string key() const noexcept
-		{
-			return json_object_iter_key(m_keyIt);
-		}
-
-	public:
-		explicit inline const_iterator(const JsonObject &object, void *keyIt) noexcept
-			: m_object(object)
-			, m_keyIt(keyIt)
-		{
-		}
-
-		inline value_type operator*() const
-		{
-			auto k = key();
-
-			return value_type(k, m_object[k]);
-		}
-
-		inline Ptr<JsonValue> operator->() const
-		{
-			auto k = key();
-
-			return Ptr<JsonValue>({k, m_object[k]});
-		}
-
-		inline const_iterator &operator++() noexcept
-		{
-			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
-
-			return *this;
-		}
-
-		inline const_iterator operator++(int) noexcept
-		{
-			const_iterator save = *this;
-
-			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
-
-			return save;
-		}
-
-		inline bool operator==(const_iterator other) const noexcept
-		{
-			return m_keyIt == other.m_keyIt;
-		}
-
-		inline bool operator!=(const_iterator other) const noexcept
-		{
-			return m_keyIt != other.m_keyIt;
-		}
-	};
-
-protected:
-	using JsonValue::JsonValue;
-
-public:
-	/**
-	 * Create empty object.
-	 *
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonObject()
-		: JsonValue(json_object())
-	{
-		check();
-	}
-
-	/**
-	 * Create a JsonObject from an initializer_list.
-	 *
-	 * @param list the list of key-value pairs
-	 * @throw JsonError on allocation error
-	 */
-	inline JsonObject(std::initializer_list<value_type> list)
-		: JsonObject()
-	{
-		for (auto &v : list)
-			set(v.first, std::move(v.second));
-	}
-
-	/**
-	 * Returns an iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline iterator begin() noexcept
-	{
-		return iterator(*this, json_object_iter(m_handle.get()));
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator begin() const noexcept
-	{
-		return const_iterator(*this, json_object_iter(m_handle.get()));
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator cbegin() const noexcept
-	{
-		return const_iterator(*this, json_object_iter(m_handle.get()));
-	}
-
-	/**
-	 * Returns an iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline iterator end() noexcept
-	{
-		return iterator(*this, nullptr);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator end() const noexcept
-	{
-		return const_iterator(*this, nullptr);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator cend() const noexcept
-	{
-		return const_iterator(*this, nullptr);
-	}
-
-	/**
-	 * Check if the object contains a specific property.
-	 *
-	 * @param key the key
-	 * @return true if the object contains the key
-	 */
-	inline bool contains(const std::string &key) const noexcept
-	{
-		return json_object_get(m_handle.get(), key.c_str()) != nullptr;
-	}
-
-	/**
-	 * Get the number of items in the object.
-	 *
-	 * @return the number of items
-	 */
-	inline unsigned size() const noexcept
-	{
-		return json_object_size(m_handle.get());
-	}
-
-	/**
-	 * Remove all elements from the object.
-	 */
-	inline void clear() noexcept
-	{
-		json_object_clear(m_handle.get());
-	}
-
-	/**
-	 * Remove element `key' if exists.
-	 *
-	 * @param key the key
-	 */
-	inline void erase(const std::string &key) noexcept
-	{
-		json_object_del(m_handle.get(), key.c_str());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param it the iterator
-	 */
-	inline void erase(iterator it) noexcept
-	{
-		erase(it.key());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param it the iterator
-	 */
-	inline void erase(const_iterator it) noexcept
-	{
-		erase(it.key());
-	}
-
-	/**
-	 * Set the value as key in the object.
-	 *
-	 * @param key the key
-	 * @param value the value
-	 */
-	inline void set(const std::string &key, const JsonValue &value) noexcept
-	{
-		json_object_set(m_handle.get(), key.c_str(), value.m_handle.get());
-	}
-
-	/**
-	 * Access an object as a wrapper so that you can update its content
-	 * with convenience.
-	 *
-	 * @param key the key
-	 */
-	Ref operator[](const std::string &key);
-
-	/**
-	 * Get the value at the specified key. If the value is not found, an
-	 * empty value is returned
-	 *
-	 * @param key the key
-	 * @return the value
-	 */
-	JsonValue operator[](const std::string &key) const;
-};
-
-/**
- * @class JsonDocument
- * @brief Read files and strings to create Json values
- */
-class JsonDocument final {
-private:
-	JsonValue m_value;
-
-	JsonValue read(std::string, int flags) const;
-	JsonValue read(std::ifstream &stream, int flags) const;
-
-public:
-	/**
-	 * Construct a document from a file.
-	 *
-	 * @param stream the stream
-	 * @param flags the optional Jansson flags
-	 * @throw JsonError on errors
-	 */
-	JsonDocument(std::ifstream &fstream, int flags = 0);
-
-	/**
-	 * Construct a document from a file.
-	 *
-	 * @param stream the stream
-	 * @param flags the optional Jansson flags
-	 * @throw JsonError on errors
-	 */
-	JsonDocument(std::ifstream &&stream, int flags = 0);
-
-	/**
-	 * Construct a document from a file.
-	 *
-	 * @param stream the stream
-	 * @param flags the optional Jansson flags
-	 * @throw JsonError on errors
-	 */
-	JsonDocument(std::string content, int flags = 0);
-
-	/**
-	 * Check if the document contains an object.
-	 *
-	 * @return true if object
-	 */
-	inline bool isObject() const noexcept
-	{
-		return m_value.isObject();
-	}
-
-	/**
-	 * Check if the document contains an array.
-	 *
-	 * @return true if array
-	 */
-	inline bool isArray() const noexcept
-	{
-		return m_value.isArray();
-	}
-
-	/**
-	 * Convert the document value to object
-	 *
-	 * @return the value as object
-	 */
-	inline JsonObject toObject() const noexcept
-	{
-		return m_value.toObject();
-	}
-
-	/**
-	 * Convert the document value to array
-	 *
-	 * @return the value as array
-	 */
-	inline JsonArray toArray() const noexcept
-	{
-		return m_value.toArray();
-	}
-};
-
-#endif // !_JSON_H_
--- a/C++/OptionParser.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/*
- * OptionParser.cpp -- command line option parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <algorithm>
-
-#include "OptionParser.h"
-
-bool OptionParser::isShort(const std::string &arg) const
-{
-	return arg.size() >= 2 && arg[0] == '-' && arg[1] != '-';
-}
-
-bool OptionParser::isLong(const std::string &arg) const
-{
-	return arg.size() >= 3 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-';
-}
-
-bool OptionParser::isOption(const std::string &arg) const
-{
-	return isShort(arg) || isLong(arg);
-}
-
-std::string OptionParser::key(const std::string &arg) const
-{
-	if (isShort(arg))
-		return arg.substr(1, 1);
-
-	return arg.substr(2);
-}
-
-bool OptionParser::isShortCompacted(const std::string &arg) const
-{
-	return arg.size() >= 3;
-}
-
-bool OptionParser::isDefined(const std::string &arg) const
-{
-	auto n = key(arg);
-	auto it = std::find_if(m_options.begin(), m_options.end(), [&] (const Option &o) -> bool {
-		return o.key() == n || o.full() == n;
-	});
-
-	return it != m_options.end();
-}
-
-const Option &OptionParser::get(const std::string &arg) const
-{
-	std::string n = key(arg);
-
-	return *std::find_if(m_options.begin(), m_options.end(), [&] (const Option &o) -> bool {
-		return o.key() == n || o.full() == n;
-	});
-}
-
-bool OptionParser::isToggle(const std::string &arg) const
-{
-	return (get(arg).flags() & Option::NoArg);
-}
-
-void OptionParser::readShort(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const
-{
-	/*
-	 * There are many options when passing a short option:
-	 *
-	 * 1. -cmyconfig	Takes on argument but parsed as unique,
-	 * 2. -c myconfig	Takes on argument but parsed as two strings
-	 * 3. -abc		If a is not a toggle option, its argument is `bc'
-	 * 4. -abc		If a is a toggle option and b, c are toggle, they are added
-	 */
-
-	std::string v = it->substr(2);
-	std::string k = key(*it);
-	const Option &option = get(std::string("-") + k);
-
-	if (isToggle(*it)) {
-		// 3. and optionally 4.
-		pack.push_back(OptionValue(option, ""));
-		pack.m_argsParsed += 1;
-
-		if (isShortCompacted(*it)) {
-			for (char c : v) {
-				if (!isDefined("-" + std::string(1, c))) {
-					pack.m_error = "-" + std::string(1, c) + " is not a valid option";
-					break;
-				}
-
-				const Option &sub = get("-" + std::string(1, c));
-
-				pack.push_back(OptionValue(sub, ""));
-			}
-		}
-
-		++ it;
-	} else {
-		// 1.
-		if (isShortCompacted(*it++)) {
-			pack.push_back(OptionValue(option, v));
-			pack.m_argsParsed += 1;
-		} else {
-			// 2.
-			if (it == end) {
-				pack.m_error = option.key() + " requires an option";
-			} else {
-				pack.push_back(OptionValue(option, *it++));
-				pack.m_argsParsed += 2;
-			}
-		}
-	}
-}
-
-void OptionParser::readFull(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const
-{
-	/*
-	 * Long options can't be compacted, there are only two possibilities:
-	 *
-	 * 1. --fullscreen	No argument
-	 * 2. --config foo	One argument
-	 */
-	const Option &option = get(*it);
-
-	if (!isToggle(*it)) {
-		// 2.
-		if (++it == end) {
-			pack.m_error = "--" + option.full() + " requires an option";
-		} else {
-			pack.push_back(OptionValue(option, *it++));
-			pack.m_argsParsed += 2;
-		}
-	} else {
-		pack.push_back(OptionValue(option, ""));
-		pack.m_argsParsed ++;
-
-		++ it;
-	}
-}
-
-OptionParser::OptionParser(std::initializer_list<Option> options)
-	: m_options(options.begin(), options.end())
-{
-}
-
-OptionParser::OptionParser(std::vector<Option> options)
-	: m_options(std::move(options))
-{
-}
-
-OptionPack OptionParser::parse(Args::const_iterator it, Args::const_iterator end, int flags) const
-{
-	OptionPack pack;
-
-	while (it != end) {
-		if (!isOption(*it)) {
-			if (flags & Unstrict) {
-				pack.m_argsParsed ++;
-				it ++;
-				continue;
-			} else {
-				pack.m_error = *it + " is not an option";
-				return pack;
-			}
-		}
-
-		if (!isDefined(*it)) {
-			pack.m_error = "Invalid option";
-			return pack;
-		}
-
-		if (isShort(*it)) {
-			readShort(pack, it, end);
-		} else {
-			readFull(pack, it, end);
-		}
-
-		// Read failure
-		if (pack.m_error.size() > 0) {
-			return pack;
-		}
-	}
-
-	return pack;
-}
-
-OptionPack OptionParser::parse(int argc, char **argv, int flags) const
-{
-	std::vector<std::string> args;
-
-	for (int i = 0; i < argc; ++i)
-		args.push_back(argv[i]);
-
-	return parse(args, flags);
-}
-
-OptionPack OptionParser::parse(const std::vector<std::string> &args, int flags) const
-{
-	return parse(args.begin(), args.end(), flags);
-}
--- a/C++/OptionParser.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,275 +0,0 @@
-/*
- * OptionParser.h -- command line option parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _OPTION_PARSER_H_
-#define _OPTION_PARSER_H_
-
-/**
- * @file OptionParser.h
- * @brief Command line option parser
- */
-
-#include <initializer_list>
-#include <string>
-#include <vector>
-
-/**
- * @class Option
- * @brief Option definition
- */
-class Option {
-public:
-	enum Flags {
-		NoArg	= (1 << 0),
-	};
-
-private:
-	std::string m_key;
-	std::string m_full;
-	int m_flags;
-
-public:
-	/**
-	 * Construct an option. By default, an option requires an argument
-	 * unless flags is set to NoArg.
-	 *
-	 * You <strong>must</strong> not prepend dashes to the option names.
-	 *
-	 * You don't need to set both short and long names, but you need at
-	 * least one.
-	 *
-	 * @param key the short name (e.g v)
-	 * @param full the long name (e.g verbose)
-	 * @param flags the optional flags
-	 * @see Flags
-	 */
-	inline Option(std::string key, std::string full, int flags = 0)
-		: m_key(std::move(key))
-		, m_full(std::move(full))
-		, m_flags(flags)
-	{
-	}
-
-	/**
-	 * Get the short name (e.g v)
-	 *
-	 * @return the short name
-	 */
-	inline const std::string &key() const noexcept
-	{
-		return m_key;
-	}
-
-	/**
-	 * Get the long name (e.g verbose)
-	 *
-	 * @return the long name
-	 */
-	inline const std::string &full() const noexcept
-	{
-		return m_full;
-	}
-
-	/**
-	 * Get the flags.
-	 *
-	 * @return the flags
-	 * @see Flags
-	 */
-	inline int flags() const noexcept
-	{
-		return m_flags;
-	}
-};
-
-/**
- * @class OptionValue
- * @brief Result of an option parse
- */
-class OptionValue {
-private:
-	std::string m_key;
-	std::string m_full;
-	std::string m_value;
-
-public:
-	/**
-	 * Construct an option value
-	 *
-	 * @param option the option
-	 * @param value the value
-	 */
-	inline OptionValue(const Option &option, std::string value)
-		: m_key(option.key())
-		, m_full(option.full())
-		, m_value(std::move(value))
-	{
-	}
-
-	/**
-	 * Get the value (if the option requires an argument).
-	 *
-	 * @return the value
-	 */
-	inline const std::string &value() const noexcept
-	{
-		return m_value;
-	}
-
-	friend bool operator==(const OptionValue &o1, const std::string &name);
-};
-
-/**
- * Test the option value with the specified option name.
- *
- * You can use both the short option or the long option name depending
- * on what you have registered to the OptionParser class.
- *
- * @param o the option
- * @param name the short or the full name
- * @return true if matches
- */
-inline bool operator==(const OptionValue &o, const std::string &name)
-{
-	return o.m_key == name || o.m_full == name;
-}
-
-/**
- * @class OptionPack
- * @brief Object containing results of a parse
- *
- * Because parsing bad options does not throw exceptions, this class is
- * convertible to bool and has the error contained.
- *
- * It also have the number of arguments parsed so you can cut your options
- * depending on the full command line.
- *
- * Example:
- *	-y install -d foo
- *	-y remove -f
- *
- * In that case, you can do two parsing, it will stops (unless Unstrict is set)
- * until install or remove.
- */
-class OptionPack : public std::vector<OptionValue> {
-private:
-	friend class OptionParser;
-
-	std::string m_error{"No error"};
-	int m_argsParsed{0};
-
-public:
-	/**
-	 * Get the error.
-	 *
-	 * @return the error
-	 */
-	inline const std::string &error() const noexcept
-	{
-		return m_error;
-	}
-
-	/**
-	 * Get the number of arguments parsed <strong>not the number of
-	 * options</strong>.
-	 *
-	 * @return the number of arguments parsed
-	 */
-	inline int parsed() const noexcept
-	{
-		return m_argsParsed;
-	}
-
-	/**
-	 * Convert to true on success.
-	 *
-	 * @return true on success
-	 */
-	inline operator bool() const noexcept
-	{
-		return m_error == "No error";
-	}
-};
-
-/**
- * @class OptionParser
- * @brief Base class for parsing command line options
- *
- * The option parser is a replacement for getopt(3) which is reentrant
- * and does not use globals.
- */
-class OptionParser {
-public:
-	using Map = std::vector<Option>;
-	using Args = std::vector<std::string>;
-
-	enum Flags {
-		Unstrict =	(1 << 0)
-	};
-
-private:
-	Map m_options;
-
-	const Option &get(const std::string &arg) const;
-	std::string key(const std::string &arg) const;
-	bool isDefined(const std::string &arg) const;
-	bool isToggle(const std::string &arg) const;
-	bool isShortCompacted(const std::string &arg) const;
-	bool isShort(const std::string &arg) const;
-	bool isLong(const std::string &arg) const;
-	bool isOption(const std::string &arg) const;
-	void readShort(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const;
-	void readFull(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const;
-	OptionPack parse(Args::const_iterator it, Args::const_iterator end, int flags) const;
-
-public:
-	/**
-	 * Construct an option parser from an initializer_list of options.
-	 *
-	 * @param options the list of options
-	 */
-	OptionParser(std::initializer_list<Option> options);
-
-	/**
-	 * Construct an option parser from a vector of options.
-	 *
-	 * @param options the options
-	 */
-	OptionParser(std::vector<Option> options);
-
-	/**
-	 * Parse the arguments from main arguments.
-	 *
-	 * @param argc the number of arguments
-	 * @param argv the arguments
-	 * @param flags the optional flags
-	 * @return the packed result
-	 */
-	OptionPack parse(int argc, char **argv, int flags = 0) const;
-
-	/**
-	 * Parse the arguments from a vector.
-	 *
-	 * @param args the arguments
-	 * @param flags the optional flags
-	 * @return the packed result
-	 */
-	OptionPack parse(const std::vector<std::string> &args, int flags = 0) const;
-};
-
-#endif // !_OPTION_PARSER_H_
--- a/C++/Pack.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * Pack.cpp -- binary data serialization
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "Pack.h"
-
-namespace {
-
-Pack::Endian checkMode()
-{
-	int i = 1;
-	unsigned char *ptr = reinterpret_cast<unsigned char *>(&i);
-
-	return (ptr[0] == 1) ? Pack::Little : Pack::Big;
-}
-
-} // !namespace
-
-const Pack::Endian Pack::mode = checkMode();
-
-/* --------------------------------------------------------
- * PackReader
- * -------------------------------------------------------- */
-
-PackReader::PackReader(Pack::Endian endian)
-	: m_endian(endian)
-{
-}
-
-/* --------------------------------------------------------
- * PackFileReader
- * -------------------------------------------------------- */
-
-PackFileReader::PackFileReader(const std::string &path, Pack::Endian endian)
-	: PackReader(endian)
-{
-	m_in.open(path, std::ifstream::in);
-}
-
-std::istream &PackFileReader::stream()
-{
-	return m_in;
-}
-
-/* --------------------------------------------------------
- * PackStringReader
- * -------------------------------------------------------- */
-
-PackStringReader::PackStringReader(std::string input, Pack::Endian endian)
-	: PackReader(endian)
-	, m_in(std::move(input))
-{
-}
-
-std::istream &PackStringReader::stream()
-{
-	return m_in;
-}
-
-/* --------------------------------------------------------
- * PackWriter
- * -------------------------------------------------------- */
-
-PackWriter::PackWriter(Pack::Endian endian)
-	: m_endian(endian)
-{
-}
-
-/* --------------------------------------------------------
- * PackFileWriter
- * -------------------------------------------------------- */
-
-PackFileWriter::PackFileWriter(const std::string &path, Pack::Endian endian)
-	: PackWriter(endian)
-{
-	m_out.open(path, std::ofstream::out);
-}
-
-std::ostream &PackFileWriter::stream()
-{
-	return m_out;
-}
-
-/* --------------------------------------------------------
- * PackStringWriter
- * -------------------------------------------------------- */
-
-PackStringWriter::PackStringWriter(Pack::Endian endian)
-	: PackWriter(endian)
-{
-}
-
-std::ostream &PackStringWriter::stream()
-{
-	return m_out;
-}
-
-std::string PackStringWriter::buffer() const
-{
-	return m_out.str();
-}
--- a/C++/Pack.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-/*
- * Pack.h -- binary data serialization
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _PACK_H_
-#define _PACK_H_
-
-#include <cstdint>
-#include <fstream>
-#include <memory>
-#include <sstream>
-#include <string>
-
-/**
- * @class Pack
- * @brief Serialize binary data to files
- *
- * This class write and read binary data from files. It currently
- * support:
- *	uint8_t,
- *	uint16_t,
- *	uint32_t,
- *	uint64_t
- */
-class Pack {
-private:
-	template <typename T>
-	struct IsContainer {
-		using Yes	= char [1];
-		using No	= char [2];
-
-		template <typename U>
-		static constexpr Yes &test(typename U::value_type *);
-
-		template <typename U>
-		static constexpr No &test(...);
-
-		static constexpr const bool value = sizeof (test<T>(0)) == sizeof (Yes);
-	};
-
-	friend class PackWriter;
-	friend class PackReader;
-
-public:
-	/**
-	 * @enum Endian
-	 * @brief Endian mode
-	 */
-	enum Endian {
-		Little,		//! Little endian
-		Big		//! Big endian
-	};
-
-public:
-	/**
-	 * Host system endian mode.
-	 */
-	static const Endian mode;
-
-	/**
-	 * @struct TypeInfo
-	 * @brief Type information
-	 *
-	 * Used for conversions.
-	 */
-	template <typename T>
-	struct TypeInfo {
-		static constexpr const bool convertible{false};
-		static constexpr const bool serializable{false};
-	};
-
-	/**
-	 * Helper to mark a specialization convertible.
-	 *
-	 * Already done for:
-	 *	uint8_t
-	 *	uint16_t
-	 *	uint32_t
-	 *	uint64_t
-	 *
-	 * The specialization must have the following function:
-	 *
-	 *	static void convert(T &value) noexcept
-	 */
-	struct Convertible {
-		static constexpr const bool convertible{true};
-	};
-
-	/**
-	 * Helper to mark a specialization serializable.
-	 *
-	 * The specialisation must have the following functions:
-	 *
-	 *	static void serialize(PackWriter &writer, const T &)
-	 *	static void unserialize(PackReader &reader, T &)
-	 */
-	struct Serializable {
-		static constexpr const bool serializable{true};
-	};
-
-	/**
-	 * Convert data inplace.
-	 *
-	 * @param value the value
-	 */
-	template <typename T>
-	static inline void convert(T &value) noexcept
-	{
-		static_assert(TypeInfo<T>::convertible, "unsupported type");
-
-		TypeInfo<T>::convert(value);
-	}
-};
-
-/**
- * @class PackReader
- * @brief Base abstract reader class
- */
-class PackReader {
-protected:
-	Pack::Endian m_endian;
-
-	PackReader(Pack::Endian endian);
-
-	virtual std::istream &stream() = 0;
-
-public:
-	/**
-	 * Default destructor.
-	 */
-	virtual ~PackReader() = default;
-
-	/**
-	 * Read a primitive convertible type.
-	 *
-	 * @param value the value destination
-	 * @return *this
-	 */
-	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::convertible>::type * = nullptr>
-	PackReader &operator>>(T &value)
-	{
-		stream().read(reinterpret_cast<char *>(&value), sizeof (T));
-
-		if (m_endian != Pack::mode)
-			Pack::convert(value);
-				
-		return *this;
-	}
-
-	/**
-	 * Read a serializable type.
-	 *
-	 * @param value the value destination
-	 * @return *this
-	 */
-	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::serializable>::type * = nullptr>
-	PackReader &operator>>(T &value)
-	{
-		Pack::TypeInfo<T>::unserialize(*this, value);
-
-		return *this;
-	}
-
-	/**
-	 * Read an array.
-	 *
-	 * This operator is a little bit tricky because you don't  know in
-	 * advance how much data you want to read. Because of that, this
-	 * function looks the capacity of the container and reads that number
-	 * of data.
-	 *
-	 * Because it looks for capacity, you can't use a container which
-	 * already have some data, they will be overriden.
-	 *
-	 * If this is a concern, you should roll your own loop to fill up
-	 * your container.
-	 *
-	 * @param container the container (all previous data will be lost)
-	 * @return *this
-	 */
-	template <typename T, typename std::enable_if<Pack::IsContainer<T>::value>::type * = nullptr>
-	PackReader &operator>>(T &container)
-	{
-		typename T::value_type v;
-
-		T copy;
-
-		for (size_t i = 0; i < container.capacity(); ++i) {
-			(*this) >> v;
-			copy.push_back(v);
-		}
-
-		container = std::move(copy);
-
-		return *this;
-	}
-};
-
-/**
- * @class PackWriter
- * @brief Base abstract writer class
- */
-class PackWriter {
-protected:
-	Pack::Endian m_endian;
-
-	PackWriter(Pack::Endian endian);
-
-	virtual std::ostream &stream() = 0;
-
-public:
-	/**
-	 * Default destructor.
-	 */
-	virtual ~PackWriter() = default;
-
-	/**
-	 * Write a convertible type to the stream.
-	 *
-	 * @param value the value
-	 * @return *this
-	 */
-	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::convertible>::type * = nullptr>
-	PackWriter &operator<<(T value)
-	{
-		if (m_endian != Pack::mode)
-			Pack::convert(value);
-
-		stream().write(reinterpret_cast<const char *>(&value), sizeof (T));
-				
-		return *this;
-	}
-
-	/**
-	 * Write a serializable type to the stream.
-	 *
-	 * @param value the value
-	 * @return *this
-	 */
-	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::serializable>::type * = nullptr>
-	PackWriter &operator<<(const T &value)
-	{
-		Pack::TypeInfo<T>::serialize(*this, value);
-
-		return *this;
-	}
-
-	/**
-	 * Write a container to the stream.
-	 *
-	 * @param container the container
-	 * @return *this
-	 */
-	template <typename T, typename std::enable_if<Pack::IsContainer<T>::value>::type * = nullptr>
-	PackWriter &operator<<(const T &container)
-	{
-		for (const auto &v : container)
-			(*this) << v;
-
-		return *this;
-	}
-};
-
-/**
- * @class PackFileReader
- * @brief Extract binary data from a file
- */
-class PackFileReader : public PackReader {
-private:
-	std::ifstream m_in;
-
-protected:
-	std::istream &stream() override;
-
-public:
-	/**
-	 * Read a file.
-	 *
-	 * @param path the path
-	 * @param endian the endian requested
-	 */
-	PackFileReader(const std::string &path, Pack::Endian endian);
-};
-
-/**
- * @class PackStringReader
- * @brief Extract binary data from a string
- */
-class PackStringReader : public PackReader {
-private:
-	std::istringstream m_in;
-
-	std::istream &stream() override;
-
-public:
-	/**
-	 * Read a string.
-	 *
-	 * @param input the input string
-	 * @param endian the endian requested
-	 */
-	PackStringReader(std::string input, Pack::Endian endian);
-};
-
-/**
- * @class PackFileWriter
- * @brief Write binary data to a string
- */
-class PackFileWriter : public PackWriter {
-private:
-	std::ofstream m_out;
-
-protected:
-	std::ostream &stream() override;
-
-public:
-	/**
-	 * Write to a file.
-	 *
-	 * @param path the path
-	 * @param endian the endian requested
-	 */
-	PackFileWriter(const std::string &path, Pack::Endian endian);
-};
-
-/**
- * @class PackStringWriter
- * @brief Write binary data to a string
- */
-class PackStringWriter : public PackWriter {
-private:
-	std::ostringstream m_out;
-
-	std::ostream &stream() override;
-
-public:
-	/**
-	 * Write to a string
-	 *
-	 * @param endian the endian requested
-	 */
-	PackStringWriter(Pack::Endian endian);
-
-	/**
-	 * The current buffer. Returns a copy of the string.
-	 *
-	 * @return the string
-	 */
-	std::string buffer() const;
-};
-
-template <>
-struct Pack::TypeInfo<uint8_t> : public Pack::Convertible {
-	static inline void convert(uint8_t &) noexcept
-	{
-		// uint8_t are endian independent
-	}
-};
-
-template <>
-struct Pack::TypeInfo<uint16_t> : public Pack::Convertible {
-	static inline void convert(uint16_t &v)
-	{
-		v = (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L));
-	}
-};
-
-template <>
-struct Pack::TypeInfo<uint32_t> : public Pack::Convertible {
-	static inline void convert(uint32_t &v)
-	{
-		v = ((((v) >> 24) & 0x000000FFL)
-		    | (((v) >> 8)  & 0x0000FF00L)
-		    | (((v) << 8)  & 0x00FF0000L)
-		    | (((v) << 24) & 0xFF000000L));
-	}
-};
-
-template <>
-struct Pack::TypeInfo<uint64_t> : public Pack::Convertible {
-	static inline void convert(uint64_t &v)
-	{
-		v = ((((v) & 0xff00000000000000ull) >> 56)
-			| (((v) & 0x00ff000000000000ull) >> 40)
-			| (((v) & 0x0000ff0000000000ull) >> 24)
-			| (((v) & 0x000000ff00000000ull) >> 8 )
-			| (((v) & 0x00000000ff000000ull) << 8 )
-			| (((v) & 0x0000000000ff0000ull) << 24)
-			| (((v) & 0x000000000000ff00ull) << 40)
-			| (((v) & 0x00000000000000ffull) << 56));
-	}
-};
-
-#endif // !_PACK_H_
--- a/C++/Parser.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-/*
- * Parser.h -- config file parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cstring>
-#include <cerrno>
-#include <iostream>
-#include <fstream>
-
-#include "Parser.h"
-
-/* --------------------------------------------------------
- * Section public members
- * -------------------------------------------------------- */
-
-Section::Section()
-	: m_allowed(true)
-{
-}
-
-Section::Section(const std::string &name, bool allowed)
-	: m_name(name)
-	, m_allowed(allowed)
-{
-
-}
-
-const std::string &Section::getName() const
-{
-	return m_name;
-}
-
-bool Section::hasOption(const std::string &name) const
-{
-	return m_options.count(name) >= 1;
-}
-
-Section::Map::iterator Section::begin()
-{
-	return m_options.begin();
-}
-
-Section::Map::const_iterator Section::cbegin() const
-{
-	return m_options.cbegin();
-}
-
-Section::Map::iterator Section::end()
-{
-	return m_options.end();
-}
-
-Section::Map::const_iterator Section::cend() const
-{
-	return m_options.end();
-}
-
-bool operator==(const Section &s1, const Section &s2)
-{
-	return s1.m_name == s2.m_name && s1.m_options == s2.m_options;
-}
-
-/* --------------------------------------------------------
- * Parser private members
- * -------------------------------------------------------- */
-
-void Parser::addOption(const std::string &key, const std::string &value)
-{
-	m_sections.back().m_options.insert(std::make_pair(key, value));
-}
-
-void Parser::readSection(int lineno, const std::string &line)
-{
-	size_t end;
-
-	if ((end = line.find_first_of(']')) != std::string::npos) {
-		if (end > 1) {
-			auto name = line.substr(1, end - 1);
-
-			/*
-			 * Check if we can add a section, if redefinition is
-			 * disabled, we must disable the previous section so the
-			 * further read options should not be enabled until
-			 * a correct section is found again.
-			 */
-			if (hasSection(name) && (m_tuning & DisableRedefinition)) {
-				if (!(m_tuning & DisableVerbosity))
-					log(lineno, name, "redefinition not allowed");
-				m_sections.back().m_allowed = false;
-			} else {
-				m_sections.push_back(Section(name));
-			}
-		} else if (!(m_tuning & DisableVerbosity)) {
-			/*
-			 * Do not add options at this step because it will
-			 * corrupt the previous one.
-			 */
-			m_sections.back().m_allowed = false;
-			log(lineno, "", "empty section name");
-		}
-	}
-}
-
-void Parser::readOption(int lineno, const std::string &line)
-{
-	auto &current = m_sections.back();
-	size_t epos;
-	std::string key, value;
-
-	// Error on last section?
-	if (!current.m_allowed) {
-		/*
-		 * If it is the root section, this has been probably set by
-		 * DisableRootSection flag, otherwise an error has occured
-		 * so no need to log.
-		 */
-		if (current.m_name == "" && !(m_tuning == DisableVerbosity))
-			log(lineno, "", "option not allowed in that scope");
-
-		return;
-	}
-
-	if ((epos = line.find_first_of('=')) == std::string::npos) {
-		if (!(m_tuning & DisableVerbosity))
-			log(lineno, current.m_name, "missing `=' keyword");
-		return;
-	}
-
-	if (epos > 0) {
-		size_t i, begin, last;
-		char c;
-
-		key = line.substr(0, epos);
-		value = line.substr(epos + 1);
-
-		// clean option key
-		for (i = 0; !isspace(key[i]) && i < key.length(); ++i)
-			continue;
-		key = key.substr(0, i);
-
-		// clean option value
-		for (begin = 0; isspace(value[begin]) && begin < value.length(); ++begin)
-			continue;
-		value = value.substr(begin);
-	
-		c = value[0];
-		begin = 0;
-		if (c == '\'' || c == '"') {
-			for (last = begin = 1; value[last] != c && last < value.length(); ++last)
-				continue;
-			if (value[last] != c && !(m_tuning & DisableVerbosity))
-				if (!(m_tuning & DisableVerbosity))
-					log(lineno, current.m_name, "undisclosed std::string");
-		} else {
-			for (last = begin; !isspace(value[last]) && last < value.length(); ++last)
-				continue;
-		}
-
-		if (last - begin > 0)
-			value = value.substr(begin, last - begin);
-		else
-			value.clear();
-
-		// Add the option if the key is not empty
-		if (key.length() > 0)
-			addOption(key, value);
-	}
-}
-
-void Parser::readLine(int lineno, const std::string &line)
-{
-	size_t i;
-	std::string buffer;
-
-	// Skip default spaces
-	for (i = 0; isspace(line[i]) && i < line.length(); ++i)
-		continue;
-
-	buffer = line.substr(i);
-	if (buffer.length() > 0) {
-		if (buffer[0] != m_commentChar) {
-			if (buffer[0] == '[')
-				readSection(lineno, buffer);
-			else
-				readOption(lineno, buffer);
-		}
-	}
-}
-
-/* --------------------------------------------------------
- * Parser public methods
- * -------------------------------------------------------- */
-
-const char Parser::DEFAULT_COMMENT_CHAR = '#';
-
-void Parser::open()
-{
-	std::ifstream file;
-	std::string line;
-	int lineno = 1;
-
-	file.open(m_path.c_str());
-	if (!file.is_open())
-		throw std::runtime_error(m_path + ": " + std::string(std::strerror(errno)));
-
-	while (std::getline(file, line))
-		readLine(lineno++, line);
-
-	file.close();
-}
-
-Parser::Parser()
-{
-}
-
-Parser::Parser(const std::string &path, int tuning, char commentToken)
-	: m_path(path)
-	, m_tuning(tuning)
-	, m_commentChar(commentToken)
-{
-	m_sections.push_back(Section("", (tuning & DisableRootSection) ? false : true));
-	open();
-}
-
-Parser::~Parser()
-{
-}
-
-Parser::List::iterator Parser::begin()
-{
-	return m_sections.begin();
-}
-
-Parser::List::const_iterator Parser::cbegin() const
-{
-	return m_sections.cbegin();
-}
-
-Parser::List::iterator Parser::end()
-{
-	return m_sections.end();
-}
-
-Parser::List::const_iterator Parser::cend() const
-{
-	return m_sections.end();
-}
-
-void Parser::findSections(const std::string &name, FindFunc func) const
-{
-	for (const auto &s : m_sections)
-		if (s.m_name == name)
-			func(s);
-}
-
-bool Parser::hasSection(const std::string &name) const
-{
-	for (const auto &s : m_sections)
-		if (s.m_name == name)
-			return true;
-
-	return false;
-}
-
-const Section &Parser::getSection(const std::string &name) const
-{
-	for (const auto &s : m_sections)
-		if (s.m_name == name)
-			return s;
-
-	throw std::out_of_range(name + " not found");
-}
-
-void Parser::log(int number, const std::string &, const std::string &message)
-{
-	std::cout << "line " << number << ": " << message << std::endl;
-}
-
-bool operator==(const Parser &p1, const Parser &p2)
-{
-	return p1.m_sections == p2.m_sections &&
-	    p1.m_path == p2.m_path &&
-	    p1.m_tuning == p2.m_tuning &&
-	    p1.m_commentChar == p2.m_commentChar;
-}
--- a/C++/Parser.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-/*
- * Parser.h -- config file parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _PARSER_H_
-#define _PARSER_H_
-
-#include <cstdlib>
-#include <functional>
-#include <stdexcept>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-/**
- * @class Section
- * @brief The option container
- *
- * A list of section found in the file. If root
- * options are allowed (default behavior), the root
- * section is "".
- */
-class Section {
-public:
-	friend class Parser;
-
-	using Map = std::unordered_map<std::string, std::string>;
-
-	template <typename T>
-	struct Converter {
-		static const bool supported = false;
-	};
-
-private:
-	std::string	m_name;		/*! name of section */
-	Map		m_options;	/*! list of options inside */
-	bool		m_allowed;	/*! is authorized to push */
-
-public:
-	/**
-	 * Default constructor.
-	 */
-	Section();
-
-	/**
-	 * Named constructor.
-	 *
-	 * @param name the section name
-	 * @param allowed is allowed to push
-	 */
-	Section(const std::string &name, bool allowed = true);
-
-	/**
-	 * Tells if that section has the specified option name.
-	 *
-	 * @param name the option name
-	 * @return true if has
-	 */
-	bool hasOption(const std::string &name) const;
-
-	/**
-	 * Get the section name
-	 *
-	 * @return the section name
-	 */
-	const std::string &getName() const;
-
-	/**
-	 * Return an iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	Map::iterator begin();
-
-	/**
-	 * Return a const iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	Map::const_iterator cbegin() const;
-
-	/**
-	 * Return an iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	Map::iterator end();
-	
-	/**
-	 * Return a const iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	Map::const_iterator cend() const;
-
-	/**
-	 * Template all functions for retrieving options value.
-	 *
-	 * @param name the option name
-	 * @return the value if found
-	 */
-	template <typename T>
-	T getOption(const std::string &name) const
-	{
-		try {
-			return requireOption<T>(name);
-		} catch (...) {
-			// Catch any conversion error.
-		}
-
-		return T();
-	}
-
-	/**
-	 * Requires an option, this works like getOption except
-	 * that if an option is not found, an exception is
-	 * thrown.
-	 *
-	 * @param name the name
-	 * @return the value
-	 * @throw std::out_of_range if not found
-	 * @throw std::invalid_argument on conversion failures
-	 */
-	template <typename T>
-	T requireOption(const std::string &name) const
-	{
-		static_assert(Converter<T>::supported, "invalid type requested");
-
-		return Converter<T>::convert(m_options.at(name));
-	}
-
-	friend bool operator==(const Section &s1, const Section &s2);
-};
-
-template <>
-struct Section::Converter<bool> {
-	static const bool supported = true;
-
-	static bool convert(const std::string &value)
-	{
-		bool result(false);
-
-		if (value == "yes" || value == "true"|| value == "1")
-			result = true;
-		else if (value == "no" || value == "false" || value == "0")
-			result = false;
-
-		return result;
-	}
-};
-
-template <>
-struct Section::Converter<int> {
-	static const bool supported = true;
-
-	static int convert(const std::string &value)
-	{
-		return std::stoi(value);
-	}
-};
-
-template <>
-struct Section::Converter<float> {
-	static const bool supported = true;
-
-	static float convert(const std::string &value)
-	{
-		return std::stof(value);
-	}
-};
-
-template <>
-struct Section::Converter<double> {
-	static const bool supported = true;
-
-	static double convert(const std::string &value)
-	{
-		return std::stod(value);
-	}
-};
-
-template <>
-struct Section::Converter<std::string> {
-	static const bool supported = true;
-
-	static std::string convert(const std::string &value)
-	{
-		return value;
-	}
-};
-
-/**
- * @class Parser
- * @brief Config file parser
- *
- * Open and read .ini files.
- */
-class Parser {
-public:
-	/**
-	 * Options available for the parser.
-	 */
-	enum Tuning {
-		DisableRootSection	= 1,	/*! disable options on root */
-		DisableRedefinition	= 2,	/*! disable multiple redefinition */
-		DisableVerbosity	= 4	/*! be verbose by method */
-	};
-
-	using FindFunc	= std::function<void (const Section &)>;
-	using List	= std::vector<Section>;
-
-private:
-	List		m_sections;		/*! list of sections found */
-	std::string	m_path;			/*! path file */
-	int		m_tuning;		/*! options for parsing */
-	char		m_commentChar;		/*! the comment token default (#) */
-
-	void addSection(const std::string &name);
-	void addOption(const std::string &key, const std::string &value);
-
-	void readSection(int lineno, const std::string &line);
-	void readOption(int lineno, const std::string &line);
-
-	void readLine(int lineno, const std::string &line);
-
-	void open();
-
-public:
-	static const char DEFAULT_COMMENT_CHAR;
-
-	/**
-	 * Create a parser at the specified file path. Optional
-	 * options may be added.
-	 *
-	 * @param path the file path
-	 * @param tuning optional tuning flags
-	 * @param commentToken an optional comment delimiter
-	 * @throw std::runtime_error on errors
-	 * @see Tuning
-	 */
-	Parser(const std::string &path, int tuning = 0, char commentToken = Parser::DEFAULT_COMMENT_CHAR);
-
-	/**
-	 * Default constructor.
-	 */
-	Parser();
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~Parser();
-
-	/**
-	 * Return an iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	List::iterator begin();
-
-	/**
-	 * Return a const iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	List::const_iterator cbegin() const;
-
-	/**
-	 * Return an iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	List::iterator end();
-	
-	/**
-	 * Return a const iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	List::const_iterator cend() const;
-
-	/**
-	 * Find all sections matching the name.
-	 *
-	 * @param name the sections name
-	 * @param func the function 
-	 * @return a list of section with the options
-	 */
-	void findSections(const std::string &name, FindFunc func) const;
-
-	/**
-	 * Tell if a section is existing.
-	 *
-	 * @return true if exists
-	 */
-	bool hasSection(const std::string &name) const;
-
-	/**
-	 * Get a specified section.
-	 *
-	 * @param name the section name
-	 * @return a section
-	 * @throw std::out_of_range if not found
-	 */
-	const Section &getSection(const std::string &name) const;
-
-	/**
-	 * Logging function, used only if DisableVerbosity is not set. The
-	 * default behavior is to print to stdout something like:
-	 * line 10: syntax error
-	 * line 8: missing =
-	 *
-	 * @param number the line number
-	 * @param section the current section worked on
-	 * @param message the message
-	 */
-	virtual void log(int number, const std::string &section, const std::string &message);
-
-	friend bool operator==(const Parser &p1, const Parser &p2);
-};
-
-#endif // !_PARSER_H_
--- a/C++/Socket.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-/*
- * Socket.cpp -- portable C++ socket wrappers
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cstring>
-
-#include "Socket.h"
-#include "SocketAddress.h"
-
-/* --------------------------------------------------------
- * System dependent code
- * -------------------------------------------------------- */
-
-#if defined(_WIN32)
-
-std::string Socket::syserror(int errn)
-{
-	LPSTR str = nullptr;
-	std::string errmsg = "Unknown error";
-
-	FormatMessageA(
-		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-		NULL,
-		errn,
-		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-		(LPSTR)&str, 0, NULL);
-
-
-	if (str) {
-		errmsg = std::string(str);
-		LocalFree(str);
-	}
-
-	return errmsg;
-}
-
-#else
-
-#include <cerrno>
-
-std::string Socket::syserror(int errn)
-{
-	return strerror(errn);
-}
-
-#endif
-
-std::string Socket::syserror()
-{
-#if defined(_WIN32)
-	return syserror(WSAGetLastError());
-#else
-	return syserror(errno);
-#endif
-}
-
-/* --------------------------------------------------------
- * SocketError class
- * -------------------------------------------------------- */
-
-SocketError::SocketError(Code code, std::string function)
-	: m_code(code)
-	, m_function(std::move(function))
-	, m_error(Socket::syserror())
-{
-}
-
-SocketError::SocketError(Code code, std::string function, int error)
-	: m_code(code)
-	, m_function(std::move(function))
-	, m_error(Socket::syserror(error))
-{
-}
-
-SocketError::SocketError(Code code, std::string function, std::string error)
-	: m_code(code)
-	, m_function(std::move(function))
-	, m_error(std::move(error))
-{
-}
-
-/* --------------------------------------------------------
- * Socket class
- * -------------------------------------------------------- */
-
-#if defined(_WIN32)
-std::mutex Socket::s_mutex;
-std::atomic<bool> Socket::s_initialized{false};
-#endif
-
-Socket::Socket(int domain, int type, int protocol)
-{
-#if defined(_WIN32) && !defined(SOCKET_NO_WSA_INIT)
-	if (!s_initialized)
-		initialize();
-#endif
-
-	m_handle = ::socket(domain, type, protocol);
-
-	if (m_handle == Invalid)
-		throw SocketError(SocketError::System, "socket");
-
-	m_state = SocketState::Opened;
-}
-
-void Socket::bind(const SocketAddress &address)
-{
-	const auto &sa = address.address();
-	const auto addrlen = address.length();
-
-	if (::bind(m_handle, reinterpret_cast<const sockaddr *>(&sa), addrlen) == Error)
-		throw SocketError(SocketError::System, "bind");
-
-	m_state = SocketState::Bound;
-}
-
-void Socket::close()
-{
-#if defined(_WIN32)
-	::closesocket(m_handle);
-#else
-	::close(m_handle);
-#endif
-
-	SocketState::Closed;
-}
-
-void Socket::setBlockMode(bool block)
-{
-#if defined(O_NONBLOCK) && !defined(_WIN32)
-	int flags;
-
-	if ((flags = fcntl(m_handle, F_GETFL, 0)) == -1)
-		flags = 0;
-
-	if (block)
-		flags &= ~(O_NONBLOCK);
-	else
-		flags |= O_NONBLOCK;
-
-	if (fcntl(m_handle, F_SETFL, flags) == Error)
-		throw SocketError(SocketError::System, "setBlockMode");
-#else
-	unsigned long flags = (block) ? 0 : 1;
-
-	if (ioctlsocket(m_handle, FIONBIO, &flags) == Error)
-		throw SocketError(SocketError::System, "setBlockMode");
-#endif
-}
-
-bool operator==(const Socket &s1, const Socket &s2)
-{
-	return s1.handle() == s2.handle();
-}
-
-bool operator<(const Socket &s1, const Socket &s2)
-{
-	return s1.handle() < s2.handle();
-}
--- a/C++/Socket.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,404 +0,0 @@
-/*
- * Socket.h -- portable C++ socket wrappers
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKET_NG_H_
-#define _SOCKET_NG_H_
-
-/**
- * @file Socket.h
- * @brief Portable socket abstraction
- *
- * User may set the following variables before compiling these files:
- *
- * SOCKET_NO_WSA_INIT	- (bool) Set to false if you don't want Socket class to
- *			  automatically calls WSAStartup() when creating sockets.
- *
- *			  Otherwise, you will need to call Socket::init,
- *			  Socket::finish yourself.
- *
- * SOCKET_NO_SSL_INIT	- (bool) Set to false if you don't want OpenSSL to be
- *			  initialized when the first SocketSsl object is created.
- *
- * SOCKET_HAVE_POLL	- (bool) Set to true if poll(2) function is available.
- *
- *			  Note: on Windows, this is automatically set if the
- *			  _WIN32_WINNT variable is greater or equal to 0x0600.
- */
-
-#include <cstring>
-#include <exception>
-#include <string>
-
-#if defined(_WIN32)
-#  include <atomic>
-#  include <cstdlib>
-#  include <mutex>
-
-#  include <WinSock2.h>
-#  include <WS2tcpip.h>
-#else
-#  include <cerrno>
-
-#  include <sys/ioctl.h>
-#  include <sys/socket.h>
-#  include <sys/types.h>
-
-#  include <arpa/inet.h>
-
-#  include <netinet/in.h>
-
-#  include <fcntl.h>
-#  include <netdb.h>
-#  include <unistd.h>
-#endif
-
-class SocketAddress;
-
-/**
- * @class SocketError
- * @brief Base class for sockets error
- */
-class SocketError : public std::exception {
-public:
-	enum Code {
-		WouldBlockRead,		///!< The operation would block for reading
-		WouldBlockWrite,	///!< The operation would block for writing
-		Timeout,		///!< The action did timeout
-		System			///!< There is a system error
-	};
-
-	Code m_code;
-	std::string m_function;
-	std::string m_error;
-
-	/**
-	 * Constructor that use the last system error.
-	 *
-	 * @param code which kind of error
-	 * @param function the function name
-	 */
-	SocketError(Code code, std::string function);
-
-	/**
-	 * Constructor that use the system error set by the user.
-	 *
-	 * @param code which kind of error
-	 * @param function the function name
-	 * @param error the error
-	 */
-	SocketError(Code code, std::string function, int error);
-
-	/**
-	 * Constructor that set the error specified by the user.
-	 *
-	 * @param code which kind of error
-	 * @param function the function name
-	 * @param error the error
-	 */
-	SocketError(Code code, std::string function, std::string error);
-
-	/**
-	 * Get which function has triggered the error.
-	 *
-	 * @return the function name (e.g connect)
-	 */
-	inline const std::string &function() const noexcept
-	{
-		return m_function;
-	}
-
-	/**
-	 * The error code.
-	 *
-	 * @return the code
-	 */
-	inline Code code() const noexcept
-	{
-		return m_code;
-	}
-
-	/**
-	 * Get the error (only the error content).
-	 *
-	 * @return the error
-	 */
-	const char *what() const noexcept
-	{
-		return m_error.c_str();
-	}
-};
-
-/**
- * @enum SocketState
- * @brief Category of error
- */
-enum class SocketState {
-	Opened,				///!< Socket is opened
-	Closed,				///!< Socket has been closed
-	Bound,				///!< Socket is bound to address
-	Connected,			///!< Socket is connected to an end point
-	Disconnected,			///!< Socket is disconnected
-	Timeout				///!< Timeout has occured in a waiting operation
-};
-
-/**
- * @class Socket
- * @brief Base socket class for socket operations
- */
-class Socket {
-public:
-	/* {{{ Portable types */
-
-	/*
-	 * The following types are defined differently between Unix
-	 * and Windows.
-	 */
-#if defined(_WIN32)
-	using Handle	= SOCKET;
-	using ConstArg	= const char *;
-	using Arg	= char *;
-#else
-	using Handle	= int;
-	using ConstArg	= const void *;
-	using Arg	= void *;
-#endif
-
-	/* }}} */
-
-	/* {{{ Portable constants */
-
-	/*
-	 * The following constants are defined differently from Unix
-	 * to Windows.
-	 */
-#if defined(_WIN32)
-	static constexpr const int Invalid	= INVALID_SOCKET;
-	static constexpr const int Error	= SOCKET_ERROR;
-#else
-	static constexpr const int Invalid	= -1;
-	static constexpr const int Error	= -1;
-#endif
-
-	/* }}} */
-
-	/* {{{ Portable initialization */
-
-	/*
-	 * Initialization stuff.
-	 *
-	 * The function init and finish are threadsafe.
-	 */
-#if defined(_WIN32)
-private:
-	static std::mutex s_mutex;
-	static std::atomic<bool> s_initialized;
-
-public:
-	static inline void finish() noexcept
-	{
-		WSACleanup();
-	}
-
-	static inline void init() noexcept
-	{
-		std::lock_guard<std::mutex> lock(s_mutex);
-
-		if (!s_initialized) {
-			s_initialized = true;
-
-			WSADATA wsa;
-			WSAStartup(MAKEWORD(2, 2), &wsa);
-
-			/*
-			 * If SOCKET_WSA_NO_INIT is not set then the user
-			 * must also call finish himself.
-			 */
-#if !defined(SOCKET_WSA_NO_INIT)
-			std::atexit(finish);
-#endif
-		}
-	}
-#else
-public:
-	/**
-	 * no-op.
-	 */
-	static inline void init() noexcept {}
-
-	/**
-	 * no-op.
-	 */
-	static inline void finish() noexcept {}
-#endif
-
-	/* }}} */
-
-protected:
-	Handle m_handle;
-	SocketState m_state{SocketState::Opened};
-
-public:
-	/**
-	 * Get the last socket system error. The error is set from errno or from
-	 * WSAGetLastError on Windows.
-	 *
-	 * @return a string message
-	 */
-	static std::string syserror();
-
-	/**
-	 * Get the last system error.
-	 *
-	 * @param errn the error number (errno or WSAGetLastError)
-	 * @return the error
-	 */
-	static std::string syserror(int errn);
-
-	/**
-	 * Construct a socket with an already created descriptor.
-	 *
-	 * @param handle the native descriptor
-	 */
-	inline Socket(Handle handle)
-		: m_handle(handle)
-		, m_state(SocketState::Opened)
-	{
-	}
-
-	/**
-	 * Create a socket handle.
-	 *
-	 * @param domain the domain AF_*
-	 * @param type the type SOCK_*
-	 * @param protocol the protocol
-	 * @throw SocketError on failures
-	 */
-	Socket(int domain, int type, int protocol);
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~Socket() = default;
-
-	/**
-	 * Set an option for the socket.
-	 *
-	 * @param level the setting level
-	 * @param name the name
-	 * @param arg the value
-	 * @throw SocketError on error
-	 */
-	template <typename Argument>
-	inline void set(int level, int name, const Argument &arg)
-	{
-#if defined(_WIN32)
-		if (setsockopt(m_handle, level, name, (Socket::ConstArg)&arg, sizeof (arg)) == SOCKET_ERROR)
-#else
-		if (setsockopt(m_handle, level, name, (Socket::ConstArg)&arg, sizeof (arg)) < 0)
-#endif
-			throw SocketError(SocketError::System, "set");
-	}
-
-	/**
-	 * Get an option for the socket.
-	 *
-	 * @param level the setting level
-	 * @param name the name
-	 * @throw SocketError on error
-	 */
-	template <typename Argument>
-	inline Argument get(int level, int name)
-	{
-		Argument desired, result{};
-		socklen_t size = sizeof (result);
-
-#if defined(_WIN32)
-		if (getsockopt(m_handle, level, name, (Socket::Arg)&desired, &size) == SOCKET_ERROR)
-#else
-		if (getsockopt(m_handle, level, name, (Socket::Arg)&desired, &size) < 0)
-#endif
-			throw SocketError(SocketError::System, "get");
-
-		std::memcpy(&result, &desired, size);
-
-		return result;
-	}
-
-	/**
-	 * Get the native handle.
-	 *
-	 * @return the handle
-	 * @warning Not portable
-	 */
-	inline Handle handle() const noexcept
-	{
-		return m_handle;
-	}
-
-	/**
-	 * Get the socket state.
-	 *
-	 * @return
-	 */
-	inline SocketState state() const noexcept
-	{
-		return m_state;
-	}
-
-	/**
-	 * Bind to an address.
-	 *
-	 * @param address the address
-	 * @throw SocketError on any error
-	 */
-	void bind(const SocketAddress &address);
-
-	/**
-	 * Set the blocking mode, if set to false, the socket will be marked
-	 * **non-blocking**.
-	 *
-	 * @param block set to false to mark **non-blocking**
-	 * @throw SocketError on any error
-	 */
-	void setBlockMode(bool block);
-
-	/**
-	 * Close the socket.
-	 */
-	virtual void close();
-};
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if they equals
- */
-bool operator==(const Socket &s1, const Socket &s2);
-
-/**
- * Compare two sockets, ideal for putting in a std::map.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if s1 < s2
- */
-bool operator<(const Socket &s1, const Socket &s2);
-
-#endif // !_SOCKET_NG_H_
--- a/C++/SocketAddress.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-/*
- * SocketAddress.cpp -- socket addresses management
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <algorithm>
-#include <cstring>
-
-#include "Socket.h"
-#include "SocketAddress.h"
-
-namespace address {
-
-/* --------------------------------------------------------
- * Internet implementation
- * -------------------------------------------------------- */
-
-Internet::Internet(const std::string &host, unsigned port, int domain)
-{
-	if (host == "*") {
-		if (domain == AF_INET6) {
-			sockaddr_in6 *ptr = (sockaddr_in6 *)&m_addr;
-
-			ptr->sin6_addr = in6addr_any;
-			ptr->sin6_family = AF_INET6;
-			ptr->sin6_port = htons(port);
-
-			m_addrlen = sizeof (sockaddr_in6);
-		} else {
-			sockaddr_in *ptr = (sockaddr_in *)&m_addr;
-
-			ptr->sin_addr.s_addr = INADDR_ANY;
-			ptr->sin_family = AF_INET;
-			ptr->sin_port = htons(port);
-
-			m_addrlen = sizeof (sockaddr_in);
-		}
-	} else {
-		addrinfo hints, *res;
-
-		std::memset(&hints, 0, sizeof (addrinfo));
-		hints.ai_family = domain;
-
-		auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);
-		if (error != 0)
-			throw SocketError(SocketError::System, "getaddrinfo", gai_strerror(error));
-
-		std::memcpy(&m_addr, res->ai_addr, res->ai_addrlen);
-		m_addrlen = res->ai_addrlen;
-		freeaddrinfo(res);
-	}
-}
-
-/* --------------------------------------------------------
- * Unix implementation
- * -------------------------------------------------------- */
-
-#if !defined(_WIN32)
-
-#include <sys/un.h>
-
-Unix::Unix(const std::string &path, bool rm)
-{
-	sockaddr_un *sun = (sockaddr_un *)&m_addr;
-
-	// Silently remove the file even if it fails
-	if (rm)
-		::remove(path.c_str());
-
-	// Copy the path
-	memset(sun->sun_path, 0, sizeof (sun->sun_path));
-	strncpy(sun->sun_path, path.c_str(), sizeof (sun->sun_path) - 1);
-
-	// Set the parameters
-	sun->sun_family = AF_UNIX;
-	m_addrlen = SUN_LEN(sun);
-}
-
-#endif // _WIN32
-
-} // !address
-
-/* --------------------------------------------------------
- * SocketAddress implementation
- * -------------------------------------------------------- */
-
-SocketAddress::SocketAddress()
-	: m_addrlen(0)
-{
-	memset(&m_addr, 0, sizeof (m_addr));
-}
-
-SocketAddress::SocketAddress(const sockaddr_storage &addr, socklen_t length)
-	: m_addr(addr)
-	, m_addrlen(length)
-{
-}
-
-const sockaddr_storage &SocketAddress::address() const
-{
-	return m_addr;
-}
-
-socklen_t SocketAddress::length() const
-{
-	return m_addrlen;
-}
-
-bool operator<(const SocketAddress &s1, const SocketAddress &s2)
-{
-	const auto &array1 = reinterpret_cast<const unsigned char *>(&s1.address());
-	const auto &array2 = reinterpret_cast<const unsigned char *>(&s2.address());
-
-	return std::lexicographical_compare(array1, array1 + s1.length(), array2, array2 + s2.length());
-}
-
-bool operator==(const SocketAddress &s1, const SocketAddress &s2)
-{
-	const auto &array1 = reinterpret_cast<const unsigned char *>(&s1.address());
-	const auto &array2 = reinterpret_cast<const unsigned char *>(&s2.address());
-
-	return std::equal(array1, array1 + s1.length(), array2, array2 + s2.length());
-}
--- a/C++/SocketAddress.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
- * SocketAddress.h -- socket addresses management
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKET_ADDRESS_NG_H_
-#define _SOCKET_ADDRESS_NG_H_
-
-#include <string>
-
-#if defined(_WIN32)
-#  include <Winsock2.h>
-#  include <Ws2tcpip.h>
-#else
-#  include <sys/socket.h>
-#endif
-
-/**
- * @class SocketAddress
- * @brief base class for socket addresses
- *
- * This class is mostly used to bind, connect or getting information
- * on socket clients.
- *
- * @see Internet
- * @see Unix
- */
-class SocketAddress {
-protected:
-	sockaddr_storage m_addr;
-	socklen_t m_addrlen;
-
-public:
-	/**
-	 * Default constructor.
-	 */
-	SocketAddress();
-
-	/**
-	 * Constructor with address and size.
-	 *
-	 * @param addr the address
-	 * @param length the address length
-	 */
-	SocketAddress(const sockaddr_storage &addr, socklen_t length);
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~SocketAddress() = default;
-
-	/**
-	 * Get the address length
-	 *
-	 * @return the length
-	 */
-	socklen_t length() const;
-
-	/**
-	 * Get the address.
-	 *
-	 * @return the address
-	 */
-	const sockaddr_storage &address() const;
-
-	/**
-	 * Compare the addresses. The check is lexicographical.
-	 *
-	 * @param s1 the first address
-	 * @param s2 the second address
-	 * @return true if s1 is less than s2
-	 */
-	friend bool operator<(const SocketAddress &s1, const SocketAddress &s2);
-
-	/**
-	 * Compare the addresses.
-	 *
-	 * @param s1 the first address
-	 * @param s2 the second address
-	 * @return true if s1 == s2
-	 */
-	friend bool operator==(const SocketAddress &s1, const SocketAddress &s2);
-};
-
-namespace address {
-
-/**
- * @class Internet
- * @brief internet protocol connect class
- *
- * Create a connect address for internet protocol,
- * using getaddrinfo(3).
- */
-class Internet : public SocketAddress {
-public:
-	/**
-	 * Create an IPv4 or IPV6 end point.
-	 *
-	 * @param host the hostname
-	 * @param port the port
-	 * @param family AF_INET, AF_INET6, ...
-	 * @throw SocketError on error
-	 */
-	Internet(const std::string &host, unsigned port, int family);
-};
-
-#if !defined(_WIN32)
-
-/**
- * @class Unix
- * @brief unix family sockets
- *
- * Create an address to a specific path. Only available on Unix.
- */
-class Unix : public SocketAddress {
-public:
-	/**
-	 * Construct an address to a path.
-	 *
-	 * @param path the path
-	 * @param rm remove the file before (default: false)
-	 */
-	Unix(const std::string &path, bool rm = false);
-};
-
-#endif // ! !_WIN32
-
-} // !address
-
-#endif // !_SOCKET_ADDRESS_NG_H_
--- a/C++/SocketListener.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +0,0 @@
-/*
- * SocketListener.cpp -- portable select() wrapper
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <algorithm>
-#include <map>
-#include <set>
-#include <utility>
-#include <vector>
-
-#include "SocketListener.h"
-
-/* --------------------------------------------------------
- * Select implementation
- * -------------------------------------------------------- */
-
-namespace {
-
-/**
- * @class SelectMethod
- * @brief Implements select(2)
- *
- * This class is the fallback of any other method, it is not preferred at all for many reasons.
- */
-class SelectMethod final : public SocketListenerInterface {
-private:
-	std::map<Socket::Handle, std::pair<std::reference_wrapper<Socket>, int>> m_table;
-
-public:
-	void set(Socket &s, int direction) override
-	{
-		if (m_table.count(s.handle()) > 0) {
-			m_table.at(s.handle()).second |= direction;
-		} else {
-			m_table.insert({s.handle(), {s, direction}});
-		}
-
-	}
-
-	void unset(Socket &s, int direction) override
-	{
-		if (m_table.count(s.handle()) != 0) {
-			m_table.at(s.handle()).second &= ~(direction);
-
-			// If no read, no write is requested, remove it
-			if (m_table.at(s.handle()).second == 0) {
-				m_table.erase(s.handle());
-			}
-		}
-	}
-
-	void remove(Socket &sc) override
-	{
-		m_table.erase(sc.handle());
-	}
-
-	void clear() override
-	{
-		m_table.clear();
-	}
-
-	SocketStatus select(int ms) override
-	{
-		auto result = selectMultiple(ms);
-
-		if (result.size() == 0) {
-			throw SocketError(SocketError::System, "select", "No socket found");
-		}
-
-		return result[0];
-	}
-
-	std::vector<SocketStatus> selectMultiple(int ms) override
-	{
-		timeval maxwait, *towait;
-		fd_set readset;
-		fd_set writeset;
-
-		FD_ZERO(&readset);
-		FD_ZERO(&writeset);
-
-		Socket::Handle max = 0;
-
-		for (auto &s : m_table) {
-			if (s.second.second & SocketListener::Read) {
-				FD_SET(s.first, &readset);
-			}
-			if (s.second.second & SocketListener::Write) {
-				FD_SET(s.first, &writeset);
-			}
-
-			if (s.first > max) {
-				max = s.first;
-			}
-		}
-
-		maxwait.tv_sec = 0;
-		maxwait.tv_usec = ms * 1000;
-
-		// Set to nullptr for infinite timeout.
-		towait = (ms < 0) ? nullptr : &maxwait;
-
-		auto error = ::select(max + 1, &readset, &writeset, nullptr, towait);
-		if (error == Socket::Error) {
-			throw SocketError(SocketError::System, "select");
-		}
-		if (error == 0) {
-			throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
-		}
-
-		std::vector<SocketStatus> sockets;
-
-		for (auto &c : m_table) {
-			if (FD_ISSET(c.first, &readset)) {
-				sockets.push_back({ c.second.first, SocketListener::Read });
-			}
-			if (FD_ISSET(c.first, &writeset)) {
-				sockets.push_back({ c.second.first, SocketListener::Write });
-			}
-		}
-
-		return sockets;
-	}
-};
-
-} // !namespace
-
-/* --------------------------------------------------------
- * Poll implementation
- * -------------------------------------------------------- */
-
-#if defined(SOCKET_HAVE_POLL)
-
-#if defined(_WIN32)
-#  include <Winsock2.h>
-#  define poll WSAPoll
-#else
-#  include <poll.h>
-#endif
-
-namespace {
-
-class PollMethod final : public SocketListenerInterface {
-private:
-	std::vector<pollfd> m_fds;
-	std::map<Socket::Handle, std::reference_wrapper<Socket>> m_lookup;
-
-	inline short topoll(int direction)
-	{
-		short result(0);
-
-		if (direction & SocketListener::Read)
-			result |= POLLIN;
-		if (direction & SocketListener::Write)
-			result |= POLLOUT;
-
-		return result;
-	}
-
-	inline int todirection(short event)
-	{
-		int direction{};
-
-		/*
-		 * Poll implementations mark the socket differently regarding
-		 * the disconnection of a socket.
-		 *
-		 * At least, even if POLLHUP or POLLIN is set, recv() always
-		 * return 0 so we mark the socket as readable.
-		 */
-		if ((event & POLLIN) || (event & POLLHUP))
-			direction |= SocketListener::Read;
-		if (event & POLLOUT)
-			direction |= SocketListener::Write;
-
-		return direction;
-	}
-
-public:
-	void set(Socket &s, int direction) override
-	{
-		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const auto &pfd) { return pfd.fd == s.handle(); });
-
-		// If found, add the new direction, otherwise add a new socket
-		if (it != m_fds.end())
-			it->events |= topoll(direction);
-		else {
-			m_lookup.insert({s.handle(), s});
-			m_fds.push_back({ s.handle(), topoll(direction), 0 });
-		}
-	}
-
-	void unset(Socket &s, int direction) override
-	{
-		for (auto i = m_fds.begin(); i != m_fds.end();) {
-			if (i->fd == s.handle()) {
-				i->events &= ~(topoll(direction));
-
-				if (i->events == 0) {
-					m_lookup.erase(i->fd);
-					i = m_fds.erase(i);
-				} else {
-					++i;
-				}
-			} else
-				++i;
-		}
-	}
-
-	void remove(Socket &s) override
-	{
-		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const auto &pfd) { return pfd.fd == s.handle(); });
-
-		if (it != m_fds.end()) {
-			m_fds.erase(it);
-			m_lookup.erase(s.handle());
-		}
-	}
-
-	void clear() override
-	{
-		m_fds.clear();
-		m_lookup.clear();
-	}
-
-	SocketStatus select(int ms) override
-	{
-		auto result = poll(m_fds.data(), m_fds.size(), ms);
-		if (result == 0)
-			throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
-		if (result < 0)
-			throw SocketError(SocketError::System, "poll");
-
-		for (auto &fd : m_fds) {
-			if (fd.revents != 0) {
-				return { m_lookup.at(fd.fd), todirection(fd.revents) };
-			}
-		}
-
-		throw SocketError(SocketError::System, "select", "No socket found");
-	}
-
-	std::vector<SocketStatus> selectMultiple(int ms) override
-	{
-		auto result = poll(m_fds.data(), m_fds.size(), ms);
-		if (result == 0) {
-			throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
-		}
-		if (result < 0) {
-			throw SocketError(SocketError::System, "poll");
-		}
-
-		std::vector<SocketStatus> sockets;
-		for (auto &fd : m_fds) {
-			if (fd.revents != 0) {
-				sockets.push_back({ m_lookup.at(fd.fd), todirection(fd.revents) });
-			}
-		}
-
-		return sockets;
-	}
-};
-
-} // !namespace
-
-#endif // !_SOCKET_HAVE_POLL
-
-/* --------------------------------------------------------
- * SocketListener
- * -------------------------------------------------------- */
-
-const int SocketListener::Read{1 << 0};
-const int SocketListener::Write{1 << 1};
-
-SocketListener::SocketListener(std::initializer_list<std::pair<std::reference_wrapper<Socket>, int>> list)
-	: SocketListener()
-{
-	for (const auto &p : list)
-		set(p.first, p.second);
-}
-
-SocketListener::SocketListener(SocketMethod method)
-{
-#if defined(SOCKET_HAVE_POLL)
-	if (method == SocketMethod::Poll)
-		m_interface = std::make_unique<PollMethod>();
-	else
-#endif
-		m_interface = std::make_unique<SelectMethod>();
-
-	(void)method;
-}
-
-void SocketListener::set(Socket &sc, int flags)
-{
-	if (m_map.count(sc) > 0) {
-		m_map[sc] |= flags;
-		m_interface->set(sc, flags);
-	} else {
-		m_map.insert({sc, flags});
-		m_interface->set(sc, flags);
-	}
-}
-
-void SocketListener::unset(Socket &sc, int flags) noexcept
-{
-	if (m_map.count(sc) > 0) {
-		m_map[sc] &= ~(flags);
-		m_interface->unset(sc, flags);
-
-		// No more flags, remove it
-		if (m_map[sc] == 0) {
-			m_map.erase(sc);
-		}
-	}
-}
--- a/C++/SocketListener.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,347 +0,0 @@
-/*
- * SocketListener.h -- portable select() wrapper
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKET_LISTENER_NG_H_
-#define _SOCKET_LISTENER_NG_H_
-
-#include <chrono>
-#include <functional>
-#include <initializer_list>
-#include <map>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "Socket.h"
-
-#if defined(_WIN32)
-#  if _WIN32_WINNT >= 0x0600
-#    define SOCKET_HAVE_POLL
-#  endif
-#else
-#  define SOCKET_HAVE_POLL
-#endif
-
-/**
- * @enum SocketMethod
- * @brief The SocketMethod enum
- *
- * Select the method of polling. It is only a preferred method, for example if you
- * request for poll but it is not available, select will be used.
- */
-enum class SocketMethod {
-	Select,				//!< select(2) method, fallback
-	Poll				//!< poll(2), everywhere possible
-};
-
-/**
- * @struct SocketStatus
- * @brief The SocketStatus struct
- *
- * Result of a select call, returns the first ready socket found with its
- * direction.
- */
-class SocketStatus {
-public:
-	Socket	&socket;		//!< which socket is ready
-	int	 direction;		//!< the direction
-};
-
-/**
- * @class SocketListenerInterface
- * @brief Implement the polling method
- */
-class SocketListenerInterface {
-public:
-	/**
-	 * Default destructor.
-	 */
-	virtual ~SocketListenerInterface() = default;
-
-	/**
-	 * Add a socket with a specified direction.
-	 *
-	 * @param s the socket
-	 * @param direction the direction
-	 */
-	virtual void set(Socket &sc, int direction) = 0;
-
-	/**
-	 * Remove a socket with a specified direction.
-	 *
-	 * @param s the socket
-	 * @param direction the direction
-	 */
-	virtual void unset(Socket &sc, int direction) = 0;
-
-	/**
-	 * Remove completely a socket.
-	 *
-	 * @param sc the socket to remove
-	 */
-	virtual void remove(Socket &sc) = 0;
-
-	/**
-	 * Remove all sockets.
-	 */
-	virtual void clear() = 0;
-
-	/**
-	 * Select one socket.
-	 *
-	 * @param ms the number of milliseconds to wait, -1 means forever
-	 * @return the socket status
-	 * @throw error::Failure on failure
-	 * @throw error::Timeout on timeout
-	 */
-	virtual SocketStatus select(int ms) = 0;
-
-	/**
-	 * Select many sockets.
-	 *
-	 * @param ms the number of milliseconds to wait, -1 means forever
-	 * @return a vector of ready sockets
-	 * @throw error::Failure on failure
-	 * @throw error::Timeout on timeout
-	 */
-	virtual std::vector<SocketStatus> selectMultiple(int ms) = 0;
-};
-
-/**
- * @class SocketListener
- * @brief Synchronous multiplexing
- *
- * Convenient wrapper around the select() system call.
- *
- * This class is implemented using a bridge pattern to allow different uses
- * of listener implementation.
- *
- * Currently, poll and select() are available.
- *
- * This wrappers takes abstract sockets as non-const reference but it does not
- * own them so you must take care that sockets are still alive until the
- * SocketListener is destroyed.
- */
-class SocketListener final {
-public:
-#if defined(SOCKET_HAVE_POLL)
-	static constexpr const SocketMethod PreferredMethod = SocketMethod::Poll;
-#else
-	static constexpr const SocketMethod PreferredMethod = SocketMethod::Select;
-#endif
-
-	static const int Read;
-	static const int Write;
-
-	using Map = std::map<std::reference_wrapper<Socket>, int>;
-	using Iface = std::unique_ptr<SocketListenerInterface>;
-
-private:
-	Map m_map;
-	Iface m_interface;
-
-public:
-	/**
-	 * Move constructor.
-	 *
-	 * @param other the other object
-	 */
-	SocketListener(SocketListener &&other) = default;
-
-	/**
-	 * Move operator.
-	 *
-	 * @param other the other object
-	 * @return this
-	 */
-	SocketListener &operator=(SocketListener &&other) = default;
-
-	/**
-	 * Create a socket listener.
-	 *
-	 * @param method the preferred method
-	 */
-	SocketListener(SocketMethod method = PreferredMethod);
-
-	/**
-	 * Create a listener from a list of sockets.
-	 *
-	 * @param list the list
-	 */
-	SocketListener(std::initializer_list<std::pair<std::reference_wrapper<Socket>, int>> list);
-
-	/**
-	 * Return an iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() noexcept
-	{
-		return m_map.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() const noexcept
-	{
-		return m_map.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cbegin() const noexcept
-	{
-		return m_map.cbegin();
-	}
-
-	/**
-	 * Return an iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() noexcept
-	{
-		return m_map.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() const noexcept
-	{
-		return m_map.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cend() const noexcept
-	{
-		return m_map.cend();
-	}
-
-	/**
-	 * Add a socket to the listener.
-	 *
-	 * @param sc the socket
-	 * @param direction (may be OR'ed)
-	 */
-	void set(Socket &sc, int direction);
-
-	/**
-	 * Unset a socket from the listener, only the direction is removed
-	 * unless the two directions are requested.
-	 *
-	 * For example, if you added a socket for both reading and writing,
-	 * unsetting the write direction will keep the socket for reading.
-	 *
-	 * @param sc the socket
-	 * @param direction the direction (may be OR'ed)
-	 * @see remove
-	 */
-	void unset(Socket &sc, int direction) noexcept;
-
-	/**
-	 * Remove completely the socket from the listener.
-	 *
-	 * @param sc the socket
-	 */
-	inline void remove(Socket &sc) noexcept
-	{
-		m_map.erase(sc);
-		m_interface->remove(sc);
-	}
-
-	/**
-	 * Remove all sockets.
-	 */
-	inline void clear() noexcept
-	{
-		m_map.clear();
-		m_interface->clear();
-	}
-
-	/**
-	 * Get the number of sockets in the listener.
-	 */
-	unsigned size() const noexcept
-	{
-		return m_map.size();
-	}
-
-	/**
-	 * Select a socket. Waits for a specific amount of time specified as the duration.
-	 *
-	 * @param duration the duration
-	 * @return the socket ready
-	 */
-	template <typename Rep, typename Ratio>
-	inline SocketStatus select(const std::chrono::duration<Rep, Ratio> &duration)
-	{
-		auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-
-		return m_interface->select(cvt.count());
-	}
-
-	/**
-	 * Overload with milliseconds.
-	 *
-	 * @param timeout the optional timeout in milliseconds
-	 * @return the socket ready
-	 */
-	inline SocketStatus select(int timeout = -1)
-	{
-		return m_interface->select(timeout);
-	}
-
-	/**
-	 * Select multiple sockets.
-	 *
-	 * @param duration the duration
-	 * @return the socket ready
-	 */
-	template <typename Rep, typename Ratio>
-	inline std::vector<SocketStatus> selectMultiple(const std::chrono::duration<Rep, Ratio> &duration)
-	{
-		auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-
-		return m_interface->selectMultiple(cvt.count());
-	}
-
-	/**
-	 * Overload with milliseconds.
-	 *
-	 * @return the socket ready
-	 */
-	inline std::vector<SocketStatus> selectMultiple(int timeout = -1)
-	{
-		return m_interface->selectMultiple(timeout);
-	}
-};
-
-#endif // !_SOCKET_LISTENER_NG_H_
--- a/C++/SocketSsl.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/*
- * SocketSsl.cpp -- OpenSSL extension for sockets
- *
- * Copyright (c) 2013, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "SocketAddress.h"
-#include "SocketListener.h"
-#include "SocketSsl.h"
-
-namespace {
-
-const SSL_METHOD *sslMethod(int mflags)
-{
-	if (mflags & SocketSslOptions::All)
-		return SSLv23_method();
-	if (mflags & SocketSslOptions::SSLv3)
-		return SSLv3_method();
-	if (mflags & SocketSslOptions::TLSv1)
-		return TLSv1_method();
-
-	return SSLv23_method();
-}
-
-inline std::string sslError(int error)
-{
-	return ERR_reason_error_string(error);
-}
-
-inline int toDirection(int error)
-{
-	if (error == SocketError::WouldBlockRead)
-		return SocketListener::Read;
-	if (error ==  SocketError::WouldBlockWrite)
-		return SocketListener::Write;
-
-	return 0;
-}
-
-} // !namespace
-
-std::mutex SocketSsl::s_sslMutex;
-std::atomic<bool> SocketSsl::s_sslInitialized{false};
-
-SocketSsl::SocketSsl(Socket::Handle handle, SSL_CTX *context, SSL *ssl)
-	: SocketAbstractTcp(handle)
-	, m_context(context, SSL_CTX_free)
-	, m_ssl(ssl, SSL_free)
-{
-#if !defined(SOCKET_NO_SSL_INIT)
-	if (!s_sslInitialized)
-		sslInitialize();
-#endif
-}
-
-SocketSsl::SocketSsl(int family, int protocol, SocketSslOptions options)
-	: SocketAbstractTcp(family, protocol)
-	, m_options(std::move(options))
-{
-#if !defined(SOCKET_NO_SSL_INIT)
-	if (!s_sslInitialized)
-		sslInitialize();
-#endif
-}
-
-void SocketSsl::connect(const SocketAddress &address)
-{
-	standardConnect(address);
-
-	// Context first
-	auto context = SSL_CTX_new(sslMethod(m_options.method));
-
-	m_context = ContextHandle(context, SSL_CTX_free);
-
-	// SSL object then
-	auto ssl = SSL_new(context);
-
-	m_ssl = SslHandle(ssl, SSL_free);
-
-	SSL_set_fd(ssl, m_handle);
-
-	auto ret = SSL_connect(ssl);
-
-	if (ret <= 0) {
-		auto error = SSL_get_error(ssl, ret);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError(SocketError::WouldBlockRead, "connect", "Operation in progress");
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError(SocketError::WouldBlockWrite, "connect", "Operation in progress");
-		} else {
-			throw SocketError(SocketError::System, "connect", sslError(error));
-		}
-	}
-
-	m_state = SocketState::Connected;
-}
-
-void SocketSsl::waitConnect(const SocketAddress &address, int timeout)
-{
-	try {
-		// Initial try
-		connect(address);
-	} catch (const SocketError &ex) {
-		if (ex.code() == SocketError::WouldBlockRead || ex.code() == SocketError::WouldBlockWrite) {
-			SocketListener listener{{*this, toDirection(ex.code())}};
-
-			listener.select(timeout);
-
-			// Second try
-			connect(address);
-		} else {
-			throw;
-		}
-	}
-}
-
-SocketSsl SocketSsl::accept()
-{
-	SocketAddress dummy;
-
-	return accept(dummy);
-}
-
-SocketSsl SocketSsl::accept(SocketAddress &info)
-{
-	auto client = standardAccept(info);
-	auto context = SSL_CTX_new(sslMethod(m_options.method));
-
-	if (m_options.certificate.size() > 0)
-		SSL_CTX_use_certificate_file(context, m_options.certificate.c_str(), SSL_FILETYPE_PEM);
-	if (m_options.privateKey.size() > 0)
-		SSL_CTX_use_PrivateKey_file(context, m_options.privateKey.c_str(), SSL_FILETYPE_PEM);
-	if (m_options.verify && !SSL_CTX_check_private_key(context)) {
-		client.close();
-		throw SocketError(SocketError::System, "accept", "certificate failure");
-	}
-
-	// SSL object
-	auto ssl = SSL_new(context);
-
-	SSL_set_fd(ssl, client.handle());
-
-	auto ret = SSL_accept(ssl);
-
-	if (ret <= 0) {
-		auto error = SSL_get_error(ssl, ret);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError(SocketError::WouldBlockRead, "accept", "Operation would block");
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError(SocketError::WouldBlockWrite, "accept", "Operation would block");
-		} else {
-			throw SocketError(SocketError::System, "accept", sslError(error));
-		}
-	}
-
-	return SocketSsl(client.handle(), context, ssl);
-}
-
-unsigned SocketSsl::recv(void *data, unsigned len)
-{
-	auto nbread = SSL_read(m_ssl.get(), data, len);
-
-	if (nbread <= 0) {
-		auto error = SSL_get_error(m_ssl.get(), nbread);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError(SocketError::WouldBlockRead, "recv", "Operation would block");
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError(SocketError::WouldBlockWrite, "recv", "Operation would block");
-		} else {
-			throw SocketError(SocketError::System, "recv", sslError(error));
-		}
-	}
-
-	return nbread;
-}
-
-unsigned SocketSsl::waitRecv(void *data, unsigned len, int timeout)
-{
-	SocketListener listener{{*this, SocketListener::Read}};
-
-	listener.select(timeout);
-
-	return recv(data, len);
-}
-
-unsigned SocketSsl::send(const void *data, unsigned len)
-{
-	auto nbread = SSL_write(m_ssl.get(), data, len);
-
-	if (nbread <= 0) {
-		auto error = SSL_get_error(m_ssl.get(), nbread);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError(SocketError::WouldBlockRead, "send", "Operation would block");
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError(SocketError::WouldBlockWrite, "send", "Operation would block");
-		} else {
-			throw SocketError(SocketError::System, "send", sslError(error));
-		}
-	}
-
-	return nbread;
-}
-
-unsigned SocketSsl::waitSend(const void *data, unsigned len, int timeout)
-{
-	SocketListener listener{{*this, SocketListener::Write}};
-
-	listener.select(timeout);
-
-	return send(data, len);
-}
-
--- a/C++/SocketSsl.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,215 +0,0 @@
-/*
- * SocketSsl.h -- OpenSSL extension for sockets
- *
- * Copyright (c) 2013, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKET_SSL_NG_H_
-#define _SOCKET_SSL_NG_H_
-
-#include <atomic>
-#include <mutex>
-
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-
-#include "SocketTcp.h"
-
-/**
- * @class SocketSslOptions
- * @brief Options for SocketSsl
- */
-class SocketSslOptions {
-public:
-	/**
-	 * @brief Method
-	 */
-	enum {
-		SSLv3	= (1 << 0),
-		TLSv1	= (1 << 1),
-		All	= (0xf)
-	};
-
-	int		method{All};		//!< The method
-	std::string	certificate;		//!< The certificate path
-	std::string	privateKey;		//!< The private key file
-	bool		verify{false};		//!< Verify or not
-
-	/**
-	 * Default constructor.
-	 */
-	SocketSslOptions() = default;
-
-	/**
-	 * More advanced constructor.
-	 *
-	 * @param method the method requested
-	 * @param certificate the certificate file
-	 * @param key the key file
-	 * @param verify set to true to verify
-	 */
-	SocketSslOptions(int method, std::string certificate, std::string key, bool verify = false)
-		: method(method)
-		, certificate(std::move(certificate))
-		, privateKey(std::move(key))
-		, verify(verify)
-	{
-	}
-};
-
-/**
- * @class SocketSsl
- * @brief SSL interface for sockets
- *
- * This class derives from SocketAbstractTcp and provide SSL support through OpenSSL.
- */
-class SocketSsl : public SocketAbstractTcp {
-public:
-	using ContextHandle = std::unique_ptr<SSL_CTX, void (*)(SSL_CTX *)>;
-	using SslHandle = std::unique_ptr<SSL, void (*)(SSL *)>;
-
-private:
-	static std::mutex s_sslMutex;
-	static std::atomic<bool> s_sslInitialized;
-
-	ContextHandle m_context{nullptr, nullptr};
-	SslHandle m_ssl{nullptr, nullptr};
-	SocketSslOptions m_options;
-
-public:
-	using SocketAbstractTcp::recv;
-	using SocketAbstractTcp::waitRecv;
-	using SocketAbstractTcp::send;
-	using SocketAbstractTcp::waitSend;
-
-	/**
-	 * Close OpenSSL library.
-	 */
-	static inline void sslTerminate()
-	{
-		ERR_free_strings();
-	}
-
-	/**
-	 * Open SSL library.
-	 */
-	static inline void sslInitialize()
-	{
-		std::lock_guard<std::mutex> lock(s_sslMutex);
-
-		if (!s_sslInitialized) {
-			s_sslInitialized = true;
-
-			SSL_library_init();
-			SSL_load_error_strings();
-
-			std::atexit(sslTerminate);
-		}
-	}
-
-	/**
-	 * Create a SocketSsl from an already created one.
-	 *
-	 * @param handle the native handle
-	 * @param context the context
-	 * @param ssl the ssl object
-	 */
-	SocketSsl(Socket::Handle handle, SSL_CTX *context, SSL *ssl);
-
-	/**
-	 * Open a SSL socket with the specified family. Automatically
-	 * use SOCK_STREAM as the type.
-	 *
-	 * @param family the family
-	 * @param options the options
-	 */
-	SocketSsl(int family, int protocol, SocketSslOptions options = {});
-
-	/**
-	 * Accept a SSL TCP socket.
-	 *
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketSsl accept();
-
-	/**
-	 * Accept a SSL TCP socket.
-	 *
-	 * @param info the client information
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketSsl accept(SocketAddress &info);
-
-	/**
-	 * Accept a SSL TCP socket.
-	 *
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketSsl waitAccept(int timeout);
-
-	/**
-	 * Accept a SSL TCP socket.
-	 *
-	 * @param info the client information
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketSsl waitAccept(SocketAddress &info, int timeout);
-
-	/**
-	 * Connect to an end point.
-	 *
-	 * @param address the address
-	 * @throw SocketError on error
-	 */
-	void connect(const SocketAddress &address);
-
-	/**
-	 * Connect to an end point.
-	 *
-	 * @param timeout the maximum timeout in milliseconds
-	 * @param address the address
-	 * @throw SocketError on error
-	 */
-	void waitConnect(const SocketAddress &address, int timeout);
-
-	/**
-	 * @copydoc SocketAbstractTcp::recv
-	 */
-	unsigned recv(void *data, unsigned length) override;
-
-	/**
-	 * @copydoc SocketAbstractTcp::recv
-	 */
-	unsigned waitRecv(void *data, unsigned length, int timeout) override;
-
-	/**
-	 * @copydoc SocketAbstractTcp::recv
-	 */
-	unsigned send(const void *data, unsigned length) override;
-
-	/**
-	 * @copydoc SocketAbstractTcp::recv
-	 */
-	unsigned waitSend(const void *data, unsigned length, int timeout) override;
-};
-
-#endif // !_SOCKET_SSL_NG_H_
--- a/C++/SocketTcp.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-/*
- * SocketTcp.cpp -- portable C++ socket wrappers
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "SocketAddress.h"
-#include "SocketListener.h"
-#include "SocketTcp.h"
-
-/* --------------------------------------------------------
- * SocketAbstractTcp
- * -------------------------------------------------------- */
-
-void SocketAbstractTcp::listen(int max)
-{
-	if (::listen(m_handle, max) == Error)
-		throw SocketError(SocketError::System, "listen");
-}
-
-Socket SocketAbstractTcp::standardAccept(SocketAddress &info)
-{
-	Socket::Handle handle;
-
-	// Store the information
-	sockaddr_storage address;
-	socklen_t addrlen;
-
-	addrlen = sizeof (sockaddr_storage);
-	handle = ::accept(m_handle, reinterpret_cast<sockaddr *>(&address), &addrlen);
-
-	if (handle == Invalid) {
-#if defined(_WIN32)
-		int error = WSAGetLastError();
-
-		if (error == WSAEWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockRead, "accept", error);
-
-		throw SocketError(SocketError::System, "accept", error);
-#else
-		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockRead, "accept");
-
-		throw SocketError(SocketError::System, "accept");
-#endif
-	}
-
-	info = SocketAddress(address, addrlen);
-
-	return Socket(handle);
-}
-
-void SocketAbstractTcp::standardConnect(const SocketAddress &address)
-{
-	if (m_state == SocketState::Connected)
-		return;
-
-	auto &sa = address.address();
-	auto addrlen = address.length();
-
-	if (::connect(m_handle, reinterpret_cast<const sockaddr *>(&sa), addrlen) == Error) {
-		/*
-		 * Determine if the error comes from a non-blocking connect that cannot be
-		 * accomplished yet.
-		 */
-#if defined(_WIN32)
-		int error = WSAGetLastError();
-
-		if (error == WSAEWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockWrite, "connect", error);
-
-		throw SocketError(SocketError::System, "connect", error);
-#else
-		if (errno == EINPROGRESS)
-			throw SocketError(SocketError::WouldBlockWrite, "connect");
-
-		throw SocketError(SocketError::System, "connect");
-#endif
-	}
-
-	m_state = SocketState::Connected;
-}
-
-/* --------------------------------------------------------
- * SocketTcp
- * -------------------------------------------------------- */
-
-SocketTcp SocketTcp::accept()
-{
-	SocketAddress dummy;
-
-	return accept(dummy);
-}
-
-SocketTcp SocketTcp::accept(SocketAddress &info)
-{
-	return standardAccept(info);
-}
-
-void SocketTcp::connect(const SocketAddress &address)
-{
-	return standardConnect(address);
-}
-
-void SocketTcp::waitConnect(const SocketAddress &address, int timeout)
-{
-	if (m_state == SocketState::Connected)
-		return;
-
-	// Initial try
-	try {
-		connect(address);
-	} catch (const SocketError &ex) {
-		if (ex.code() == SocketError::WouldBlockWrite) {
-			SocketListener listener{{*this, SocketListener::Write}};
-
-			listener.select(timeout);
-
-			// Socket is writable? Check if there is an error
-
-			int error = get<int>(SOL_SOCKET, SO_ERROR);
-
-			if (error) {
-				throw SocketError(SocketError::System, "connect", error);
-			}
-		} else {
-			throw;
-		}
-	}
-
-	m_state = SocketState::Connected;
-}
-
-SocketTcp SocketTcp::waitAccept(int timeout)
-{
-	SocketAddress dummy;
-
-	return waitAccept(dummy, timeout);
-}
-
-SocketTcp SocketTcp::waitAccept(SocketAddress &info, int timeout)
-{
-	SocketListener listener{{*this, SocketListener::Read}};
-
-	listener.select(timeout);
-
-	return accept(info);
-}
-
-unsigned SocketTcp::recv(void *data, unsigned dataLen)
-{
-	int nbread;
-
-	nbread = ::recv(m_handle, (Socket::Arg)data, dataLen, 0);
-	if (nbread == Error) {
-#if defined(_WIN32)
-		int error = WSAGetLastError();
-
-		if (error == WSAEWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockRead, "recv", error)
-
-		throw SocketError(SocketError::System, "recv", error);
-#else
-		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockRead, "recv");
-
-		throw SocketError(SocketError::System, "recv");
-#endif
-	} else if (nbread == 0)
-		m_state = SocketState::Closed;
-
-	return (unsigned)nbread;
-}
-
-unsigned SocketTcp::waitRecv(void *data, unsigned length, int timeout)
-{
-	SocketListener listener{{*this, SocketListener::Read}};
-
-	listener.select(timeout);
-
-	return recv(data, length);
-}
-
-unsigned SocketTcp::send(const void *data, unsigned length)
-{
-	int nbsent;
-
-	nbsent = ::send(m_handle, (Socket::ConstArg)data, length, 0);
-	if (nbsent == Error) {
-#if defined(_WIN32)
-		int error = WSAGetLastError();
-
-		if (error == WSAEWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockWrite, "send", error);
-
-		throw SocketError(SocketError::System, "send", error);
-#else
-		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockWrite, "send");
-
-		throw SocketError(SocketError::System, "send");
-#endif
-	}
-
-	return (unsigned)nbsent;
-}
-
-unsigned SocketTcp::waitSend(const void *data, unsigned length, int timeout)
-{
-	SocketListener listener{{*this, SocketListener::Write}};
-
-	listener.select(timeout);
-
-	return send(data, length);
-}
--- a/C++/SocketTcp.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-/*
- * SocketTcp.h -- portable C++ socket wrappers
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKET_TCP_NG_H_
-#define _SOCKET_TCP_NG_H_
-
-#include "Socket.h"
-
-/**
- * @class SocketAbstractTcp
- * @brief Base class for TCP sockets
- *
- * This abstract class provides standard TCP functions for both clear
- * and SSL implementation.
- *
- * It does not contain default accept() and connect() because they varies too
- * much between standard and SSL. Also, the accept() function return different
- * types.
- */
-class SocketAbstractTcp : public Socket {
-protected:
-	Socket standardAccept(SocketAddress &address);
-	void standardConnect(const SocketAddress &address);
-
-public:
-	/**
-	 * Construct an abstract socket from an already made socket.
-	 *
-	 * @param s the socket
-	 */
-	inline SocketAbstractTcp(Socket s)
-		: Socket(s)
-	{
-	}
-
-	/**
-	 * Construct a standard TCP socket. The type is automatically
-	 * set to SOCK_STREAM.
-	 *
-	 * @param domain the domain
-	 * @param protocol the protocol
-	 * @throw SocketError on error
-	 */
-	inline SocketAbstractTcp(int domain, int protocol)
-		: Socket(domain, SOCK_STREAM, protocol)
-	{
-	}
-
-	/**
-	 * Listen for pending connection.
-	 *
-	 * @param max the maximum number
-	 */
-	void listen(int max = 128);
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param count the number of bytes to receive
-	 * @return the string
-	 * @throw SocketError on error
-	 */
-	inline std::string recv(unsigned count)
-	{
-		std::string result;
-
-		result.resize(count);
-		auto n = recv(const_cast<char *>(result.data()), count);
-		result.resize(n);
-
-		return result;
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param count the number of bytes to receive
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the string
-	 * @throw SocketError on error
-	 */
-	inline std::string waitRecv(unsigned count, int timeout)
-	{
-		std::string result;
-
-		result.resize(count);
-		auto n = waitRecv(const_cast<char *>(result.data()), count, timeout);
-		result.resize(n);
-
-		return result;
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param data the string to send
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	inline unsigned send(const std::string &data)
-	{
-		return send(data.c_str(), data.size());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param data the string to send
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	inline unsigned waitSend(const std::string &data, int timeout)
-	{
-		return waitSend(data.c_str(), data.size(), timeout);
-	}
-
-	/**
-	 * Receive data.
-	 *
-	 * @param data the destination buffer
-	 * @param length the buffer length
-	 * @return the number of bytes received
-	 * @throw SocketError on error
-	 */
-	virtual unsigned recv(void *data, unsigned length) = 0;
-
-	/**
-	 * Receive data.
-	 *
-	 * @param data the destination buffer
-	 * @param length the buffer length
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the number of bytes received
-	 * @throw SocketError on error
-	 */
-	virtual unsigned waitRecv(void *data, unsigned length, int timeout) = 0;
-
-	/**
-	 * Send data.
-	 *
-	 * @param data the buffer
-	 * @param length the buffer length
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	virtual unsigned send(const void *data, unsigned length) = 0;
-
-	/**
-	 * Send data.
-	 *
-	 * @param data the buffer
-	 * @param length the buffer length
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	virtual unsigned waitSend(const void *data, unsigned length, int timeout) = 0;
-};
-
-/**
- * @class SocketTcp
- * @brief End-user class for TCP sockets
- */
-class SocketTcp : public SocketAbstractTcp {
-public:
-	using SocketAbstractTcp::SocketAbstractTcp;
-	using SocketAbstractTcp::recv;
-	using SocketAbstractTcp::waitRecv;
-	using SocketAbstractTcp::send;
-	using SocketAbstractTcp::waitSend;
-
-	/**
-	 * Accept a clear TCP socket.
-	 *
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketTcp accept();
-
-	/**
-	 * Accept a clear TCP socket.
-	 *
-	 * @param info the client information
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketTcp accept(SocketAddress &info);
-
-	/**
-	 * Accept a clear TCP socket.
-	 *
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketTcp waitAccept(int timeout);
-
-	/**
-	 * Accept a clear TCP socket.
-	 *
-	 * @param info the client information
-	 * @param timeout the maximum timeout in milliseconds
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketTcp waitAccept(SocketAddress &info, int timeout);
-
-	/**
-	 * Connect to an end point.
-	 *
-	 * @param address the address
-	 * @throw SocketError on error
-	 */
-	void connect(const SocketAddress &address);
-
-	/**
-	 * Connect to an end point.
-	 *
-	 * @param timeout the maximum timeout in milliseconds
-	 * @param address the address
-	 * @throw SocketError on error
-	 */
-	void waitConnect(const SocketAddress &address, int timeout);
-
-	/**
-	 * @copydoc SocketAbstractTcp::recv
-	 */
-	unsigned recv(void *data, unsigned length) override;
-
-	/**
-	 * @copydoc SocketAbstractTcp::waitRecv
-	 */
-	unsigned waitRecv(void *data, unsigned length, int timeout) override;
-
-	/**
-	 * @copydoc SocketAbstractTcp::send
-	 */
-	unsigned send(const void *data, unsigned length) override;
-
-	/**
-	 * @copydoc SocketAbstractTcp::waitSend
-	 */
-	unsigned waitSend(const void *data, unsigned length, int timeout) override;
-};
-
-#endif // !_SOCKET_TCP_NG_H_
--- a/C++/SocketUdp.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * SocketUdp.cpp -- portable C++ socket wrappers
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "SocketAddress.h"
-#include "SocketUdp.h"
-
-SocketUdp::SocketUdp(int domain, int protocol)
-	: Socket(domain, SOCK_DGRAM, protocol)
-{
-}
-
-unsigned SocketUdp::recvfrom(void *data, unsigned length, SocketAddress &info)
-{
-	int nbread;
-
-	// Store information
-	sockaddr_storage address;
-	socklen_t addrlen;
-
-	addrlen = sizeof (struct sockaddr_storage);
-	nbread = ::recvfrom(m_handle, (Socket::Arg)data, length, 0, (sockaddr *)&address, &addrlen);
-
-	info = SocketAddress(address, addrlen);
-
-	if (nbread == Error) {
-#if defined(_WIN32)
-		int error = WSAGetLastError();
-
-		if (error == WSAEWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockRead, "recvfrom", error);
-
-		throw SocketError(SocketError::System, "recvfrom", error);
-#else
-		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockRead, "recvfrom");
-
-		throw SocketError(SocketError::System, "recvfrom");
-#endif
-	}
-
-	return (unsigned)nbread;
-}
-
-unsigned SocketUdp::sendto(const void *data, unsigned length, const SocketAddress &info)
-{
-	int nbsent;
-
-	nbsent = ::sendto(m_handle, (Socket::ConstArg)data, length, 0, (const sockaddr *)&info.address(), info.length());
-	if (nbsent == Error) {
-#if defined(_WIN32)
-		int error = WSAGetLastError();
-
-		if (error == WSAEWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockWrite, "sendto", error);
-
-		throw SocketError(SocketError::System, "sendto", error);
-#else
-		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw SocketError(SocketError::WouldBlockWrite, "sendto");
-
-		throw SocketError(SocketError::System, "sendto");
-#endif
-	}
-
-	return (unsigned)nbsent;
-}
--- a/C++/SocketUdp.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * SocketUdp.h -- portable C++ socket wrappers
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKET_UDP_NG_H_
-#define _SOCKET_UDP_NG_H_
-
-#include "Socket.h"
-
-/**
- * @class SocketUdp
- * @brief UDP implementation for sockets
- */
-class SocketUdp : public Socket {
-public:
-	/**
-	 * Construct a UDP socket. The type is automatically set to SOCK_DGRAM.
-	 *
-	 * @param domain the domain (e.g AF_INET)
-	 * @param protocol the protocol (usually 0)
-	 */
-	SocketUdp(int domain, int protocol);
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param data the data
-	 * @param address the address
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	inline unsigned sendto(const std::string &data, const SocketAddress &address)
-	{
-		return sendto(data.c_str(), data.length(), address);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @param data the data
-	 * @param info the client information
-	 * @return the string
-	 * @throw SocketError on error
-	 */
-	inline std::string recvfrom(unsigned count, SocketAddress &info)
-	{
-		std::string result;
-
-		result.resize(count);
-		auto n = recvfrom(const_cast<char *>(result.data()), count, info);
-		result.resize(n);
-
-		return result;
-	}
-
-	/**
-	 * Receive data from an end point.
-	 *
-	 * @param data the destination buffer
-	 * @param length the buffer length
-	 * @param info the client information
-	 * @return the number of bytes received
-	 * @throw SocketError on error
-	 */
-	virtual unsigned recvfrom(void *data, unsigned length, SocketAddress &info);
-
-	/**
-	 * Send data to an end point.
-	 *
-	 * @param data the buffer
-	 * @param length the buffer length
-	 * @param address the client address
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	virtual unsigned sendto(const void *data, unsigned length, const SocketAddress &address);
-};
-
-#endif // !_SOCKET_UDP_NG_H_
--- a/C++/Tests/Base64/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#
-# CMakeLists.txt -- tests for Base64
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Base64.cpp
-	${code_SOURCE_DIR}/C++/Base64.h
-	main.cpp
-)
-
-define_test(base64 "${SOURCES}")
-
--- a/C++/Tests/Base64/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-/*
- * main.cpp -- main test file for Base64
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <gtest/gtest.h>
-
-#include <Base64.h>
-
-TEST(Lookup, lookup)
-{
-	ASSERT_EQ('A', Base64::lookup(0b000000));
-	ASSERT_EQ('B', Base64::lookup(0b000001));
-	ASSERT_EQ('C', Base64::lookup(0b000010));
-	ASSERT_EQ('D', Base64::lookup(0b000011));
-	ASSERT_EQ('E', Base64::lookup(0b000100));
-	ASSERT_EQ('F', Base64::lookup(0b000101));
-	ASSERT_EQ('G', Base64::lookup(0b000110));
-	ASSERT_EQ('H', Base64::lookup(0b000111));
-	ASSERT_EQ('I', Base64::lookup(0b001000));
-	ASSERT_EQ('J', Base64::lookup(0b001001));
-	ASSERT_EQ('K', Base64::lookup(0b001010));
-	ASSERT_EQ('L', Base64::lookup(0b001011));
-	ASSERT_EQ('M', Base64::lookup(0b001100));
-	ASSERT_EQ('N', Base64::lookup(0b001101));
-	ASSERT_EQ('O', Base64::lookup(0b001110));
-	ASSERT_EQ('P', Base64::lookup(0b001111));
-	ASSERT_EQ('Q', Base64::lookup(0b010000));
-	ASSERT_EQ('R', Base64::lookup(0b010001));
-	ASSERT_EQ('S', Base64::lookup(0b010010));
-	ASSERT_EQ('T', Base64::lookup(0b010011));
-	ASSERT_EQ('U', Base64::lookup(0b010100));
-	ASSERT_EQ('V', Base64::lookup(0b010101));
-	ASSERT_EQ('W', Base64::lookup(0b010110));
-	ASSERT_EQ('X', Base64::lookup(0b010111));
-	ASSERT_EQ('Y', Base64::lookup(0b011000));
-	ASSERT_EQ('Z', Base64::lookup(0b011001));
-	ASSERT_EQ('a', Base64::lookup(0b011010));
-	ASSERT_EQ('b', Base64::lookup(0b011011));
-	ASSERT_EQ('c', Base64::lookup(0b011100));
-	ASSERT_EQ('d', Base64::lookup(0b011101));
-	ASSERT_EQ('e', Base64::lookup(0b011110));
-	ASSERT_EQ('f', Base64::lookup(0b011111));
-	ASSERT_EQ('g', Base64::lookup(0b100000));
-	ASSERT_EQ('h', Base64::lookup(0b100001));
-	ASSERT_EQ('i', Base64::lookup(0b100010));
-	ASSERT_EQ('j', Base64::lookup(0b100011));
-	ASSERT_EQ('k', Base64::lookup(0b100100));
-	ASSERT_EQ('l', Base64::lookup(0b100101));
-	ASSERT_EQ('m', Base64::lookup(0b100110));
-	ASSERT_EQ('n', Base64::lookup(0b100111));
-	ASSERT_EQ('o', Base64::lookup(0b101000));
-	ASSERT_EQ('p', Base64::lookup(0b101001));
-	ASSERT_EQ('q', Base64::lookup(0b101010));
-	ASSERT_EQ('r', Base64::lookup(0b101011));
-	ASSERT_EQ('s', Base64::lookup(0b101100));
-	ASSERT_EQ('t', Base64::lookup(0b101101));
-	ASSERT_EQ('u', Base64::lookup(0b101110));
-	ASSERT_EQ('v', Base64::lookup(0b101111));
-	ASSERT_EQ('w', Base64::lookup(0b110000));
-	ASSERT_EQ('x', Base64::lookup(0b110001));
-	ASSERT_EQ('y', Base64::lookup(0b110010));
-	ASSERT_EQ('z', Base64::lookup(0b110011));
-	ASSERT_EQ('0', Base64::lookup(0b110100));
-	ASSERT_EQ('1', Base64::lookup(0b110101));
-	ASSERT_EQ('2', Base64::lookup(0b110110));
-	ASSERT_EQ('3', Base64::lookup(0b110111));
-	ASSERT_EQ('4', Base64::lookup(0b111000));
-	ASSERT_EQ('5', Base64::lookup(0b111001));
-	ASSERT_EQ('6', Base64::lookup(0b111010));
-	ASSERT_EQ('7', Base64::lookup(0b111011));
-	ASSERT_EQ('8', Base64::lookup(0b111100));
-	ASSERT_EQ('9', Base64::lookup(0b111101));
-	ASSERT_EQ('+', Base64::lookup(0b111110));
-	ASSERT_EQ('/', Base64::lookup(0b111111));
-}
-
-TEST(Lookup, rlookup)
-{
-	ASSERT_EQ(0b000000, Base64::rlookup('A'));
-	ASSERT_EQ(0b000001, Base64::rlookup('B'));
-	ASSERT_EQ(0b000010, Base64::rlookup('C'));
-	ASSERT_EQ(0b000011, Base64::rlookup('D'));
-	ASSERT_EQ(0b000100, Base64::rlookup('E'));
-	ASSERT_EQ(0b000101, Base64::rlookup('F'));
-	ASSERT_EQ(0b000110, Base64::rlookup('G'));
-	ASSERT_EQ(0b000111, Base64::rlookup('H'));
-	ASSERT_EQ(0b001000, Base64::rlookup('I'));
-	ASSERT_EQ(0b001001, Base64::rlookup('J'));
-	ASSERT_EQ(0b001010, Base64::rlookup('K'));
-	ASSERT_EQ(0b001011, Base64::rlookup('L'));
-	ASSERT_EQ(0b001100, Base64::rlookup('M'));
-	ASSERT_EQ(0b001101, Base64::rlookup('N'));
-	ASSERT_EQ(0b001110, Base64::rlookup('O'));
-	ASSERT_EQ(0b001111, Base64::rlookup('P'));
-	ASSERT_EQ(0b010000, Base64::rlookup('Q'));
-	ASSERT_EQ(0b010001, Base64::rlookup('R'));
-	ASSERT_EQ(0b010010, Base64::rlookup('S'));
-	ASSERT_EQ(0b010011, Base64::rlookup('T'));
-	ASSERT_EQ(0b010100, Base64::rlookup('U'));
-	ASSERT_EQ(0b010101, Base64::rlookup('V'));
-	ASSERT_EQ(0b010110, Base64::rlookup('W'));
-	ASSERT_EQ(0b010111, Base64::rlookup('X'));
-	ASSERT_EQ(0b011000, Base64::rlookup('Y'));
-	ASSERT_EQ(0b011001, Base64::rlookup('Z'));
-	ASSERT_EQ(0b011010, Base64::rlookup('a'));
-	ASSERT_EQ(0b011011, Base64::rlookup('b'));
-	ASSERT_EQ(0b011100, Base64::rlookup('c'));
-	ASSERT_EQ(0b011101, Base64::rlookup('d'));
-	ASSERT_EQ(0b011110, Base64::rlookup('e'));
-	ASSERT_EQ(0b011111, Base64::rlookup('f'));
-	ASSERT_EQ(0b100000, Base64::rlookup('g'));
-	ASSERT_EQ(0b100001, Base64::rlookup('h'));
-	ASSERT_EQ(0b100010, Base64::rlookup('i'));
-	ASSERT_EQ(0b100011, Base64::rlookup('j'));
-	ASSERT_EQ(0b100100, Base64::rlookup('k'));
-	ASSERT_EQ(0b100101, Base64::rlookup('l'));
-	ASSERT_EQ(0b100110, Base64::rlookup('m'));
-	ASSERT_EQ(0b100111, Base64::rlookup('n'));
-	ASSERT_EQ(0b101000, Base64::rlookup('o'));
-	ASSERT_EQ(0b101001, Base64::rlookup('p'));
-	ASSERT_EQ(0b101010, Base64::rlookup('q'));
-	ASSERT_EQ(0b101011, Base64::rlookup('r'));
-	ASSERT_EQ(0b101100, Base64::rlookup('s'));
-	ASSERT_EQ(0b101101, Base64::rlookup('t'));
-	ASSERT_EQ(0b101110, Base64::rlookup('u'));
-	ASSERT_EQ(0b101111, Base64::rlookup('v'));
-	ASSERT_EQ(0b110000, Base64::rlookup('w'));
-	ASSERT_EQ(0b110001, Base64::rlookup('x'));
-	ASSERT_EQ(0b110010, Base64::rlookup('y'));
-	ASSERT_EQ(0b110011, Base64::rlookup('z'));
-	ASSERT_EQ(0b110100, Base64::rlookup('0'));
-	ASSERT_EQ(0b110101, Base64::rlookup('1'));
-	ASSERT_EQ(0b110110, Base64::rlookup('2'));
-	ASSERT_EQ(0b110111, Base64::rlookup('3'));
-	ASSERT_EQ(0b111000, Base64::rlookup('4'));
-	ASSERT_EQ(0b111001, Base64::rlookup('5'));
-	ASSERT_EQ(0b111010, Base64::rlookup('6'));
-	ASSERT_EQ(0b111011, Base64::rlookup('7'));
-	ASSERT_EQ(0b111100, Base64::rlookup('8'));
-	ASSERT_EQ(0b111101, Base64::rlookup('9'));
-	ASSERT_EQ(0b111110, Base64::rlookup('+'));
-	ASSERT_EQ(0b111111, Base64::rlookup('/'));
-}
-
-TEST(Encode, basic)
-{
-	ASSERT_EQ("YQ==", Base64::encode("a"));
-	ASSERT_EQ("YWI=", Base64::encode("ab"));
-	ASSERT_EQ("YWJj", Base64::encode("abc"));
-
-	ASSERT_EQ("aGVsbG8=", Base64::encode("hello"));
-	ASSERT_EQ("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=", Base64::encode("this is a long sentence"));
-}
-
-TEST(Decode, basic)
-{
-	ASSERT_EQ("a", Base64::decode("YQ=="));
-	ASSERT_EQ("ab", Base64::decode("YWI="));
-	ASSERT_EQ("abc", Base64::decode("YWJj"));
-
-	ASSERT_EQ("hello", Base64::decode("aGVsbG8="));
-	ASSERT_EQ("this is a long sentence", Base64::decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U="));
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Directory/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- tests for Directory
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Directory.cpp
-	${code_SOURCE_DIR}/C++/Directory.h
-	main.cpp
-)
-
-define_test(directory "${SOURCES}")
--- a/C++/Tests/Directory/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * main.cpp -- test directory
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <gtest/gtest.h>
-
-#include <Directory.h>
-
-TEST(Filter, withDot)
-{
-	try {
-		auto flags = Directory::NotDotDot;
-		Directory directory(".", flags);
-		bool dot(false);
-		bool dotdot(false);
-
-		for (const auto &entry : directory) {
-			if (entry.name == ".")
-				dot = true;
-			if (entry.name == "..")
-				dotdot = true;
-		}
-
-		ASSERT_TRUE(dot);
-		ASSERT_FALSE(dotdot);
-	} catch (const std::runtime_error &error) {
-		FAIL() << "skipping test because: " << error.what();
-	}
-}
-
-TEST(Filter, withDotDot)
-{
-	try {
-		auto flags = Directory::NotDot;
-		Directory directory(".", flags);
-		bool dot(false);
-		bool dotdot(false);
-
-		for (const auto &entry : directory) {
-			if (entry.name == ".")
-				dot = true;
-			if (entry.name == "..")
-				dotdot = true;
-		}
-
-		ASSERT_FALSE(dot);
-		ASSERT_TRUE(dotdot);
-	} catch (const std::runtime_error &error) {
-		FAIL() << "skipping test because: " << error.what();
-	}
-}
-
-TEST(Filter, withBothDots)
-{
-	try {
-		Directory directory(".");
-		bool dot(false);
-		bool dotdot(false);
-
-		for (const auto &entry : directory) {
-			if (entry.name == ".")
-				dot = true;
-			if (entry.name == "..")
-				dotdot = true;
-		}
-
-		ASSERT_TRUE(dot);
-		ASSERT_TRUE(dotdot);
-	} catch (const std::runtime_error &error) {
-		FAIL() << "skipping test because: " << error.what();
-	}
-}
-
-TEST(Filter, withoutDots)
-{
-	try {
-		auto flags = Directory::NotDot | Directory::NotDotDot;
-		Directory directory(".", flags);
-		bool dot(false);
-		bool dotdot(false);
-
-		for (const auto &entry : directory) {
-			if (entry.name == ".")
-				dot = true;
-			if (entry.name == "..")
-				dotdot = true;
-		}
-
-		ASSERT_FALSE(dot);
-		ASSERT_FALSE(dotdot);
-	} catch (const std::runtime_error &error) {
-		FAIL() << "skipping test because: " << error.what();
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
\ No newline at end of file
--- a/C++/Tests/DynLib/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-#
-# CMakeLists.txt -- tests for DynLib
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-# Plugin module
-add_library(Plugin MODULE Plugin.cpp)
-set_target_properties(
-	Plugin
-	PROPERTIES
-	PREFIX ""
-)
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/DynLib.cpp
-	${code_SOURCE_DIR}/C++/DynLib.h
-	main.cpp
-)
-
-define_test(dynlib "${SOURCES}")
-
-if (CMAKE_SYSTEM_NAME MATCHES "Linux")
-	target_link_libraries(dynlib dl)
-endif ()
-
-# The extension for the system
-if(WIN32)
-	set(EXTENSION ".dll")
-elseif(UNIX)
-	set(EXTENSION ".so")
-elseif(APPLE)
-	set(EXTENSION ".dylib")
-else()
-	message(FATAL_ERROR "Unsupported platform")
-endif()
-
-target_compile_definitions(dynlib PRIVATE "EXTENSION=\"${EXTENSION}\"")
--- a/C++/Tests/DynLib/Plugin.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-#include <string>
-
-#include <DynLib.h>
-
-extern "C" {
-
-void DYNLIB_EXPORT initialize(std::string &result)
-{
-	result = "Hello World";
-}
-
-}
--- a/C++/Tests/DynLib/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * TestDynLib.cpp -- test the dynamic library loader
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <DynLib.h>
-
-/*
- * NOTE: the EXTENSION is defined by CMake in the form of a string
- * literal containing the appropriate extension for the given system.
- */
- 
-using Initialize = void (*)(std::string &s);
-
-TEST(Basic, initialize)
-{
-	try {
-		DynLib library("./Plugin" EXTENSION);
-		Initialize init = library.sym<Initialize>("initialize");
-
-		std::string expected("Hello World");
-		std::string result;
-
-		init(result);
-		
-		ASSERT_EQ(expected, result);
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	} catch (const std::out_of_range &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(Basic, absent)
-{
-	try {
-		DynLib library("./Plugin" EXTENSION);
-		library.sym<Initialize>("initialize_typo");
-	} catch (const std::out_of_range &error) {
-		return;
-	}
-
-	FAIL() << "Expected a failure but succeed";
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
\ No newline at end of file
--- a/C++/Tests/Flags/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- tests for Flags
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Flags.h
-	main.cpp
-)
-
-define_test(flags "${SOURCES}")
\ No newline at end of file
--- a/C++/Tests/Flags/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,298 +0,0 @@
-/*
- * main.cpp -- main test file for Flags
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cstdint>
-
-#include <gtest/gtest.h>
-
-#include <Flags.h>
-
-enum Standard : uint8_t {
-	Fullscreen	= (1 << 0),
-	Audio		= (1 << 1)
-};
-
-enum class Strong : uint8_t {
-	NoLog		= (1 << 0),
-	NoCheck		= (1 << 1)
-};
-
-/* --------------------------------------------------------
- * Global operators on standard enum
- * -------------------------------------------------------- */
-
-TEST(OperatorsStandard, opand)
-{
-	Standard s(Fullscreen | Audio);
-
-	ASSERT_EQ(Fullscreen, (s & Fullscreen));
-	ASSERT_EQ(Audio, (s & Audio));
-}
-
-TEST(OperatorsStandard, opor)
-{
-	Standard s(Fullscreen);
-
-	ASSERT_EQ(3, (s | Audio));
-}
-
-TEST(OperatorsStandard, opxor)
-{
-	Standard s(Fullscreen);
-
-	ASSERT_EQ(3, (s ^ Audio));
-}
-
-TEST(OperatorsStandard, opnot)
-{
-	Standard s(Fullscreen);
-
-	ASSERT_EQ(254, ~s);
-}
-
-/* --------------------------------------------------------
- * Global operators on strong enum
- * -------------------------------------------------------- */
-
-TEST(OperatorsStrong, opand)
-{
-	Strong s(Strong::NoLog | Strong::NoCheck);
-
-	ASSERT_EQ(Strong::NoLog, (s & Strong::NoLog));
-	ASSERT_EQ(Strong::NoCheck, (s & Strong::NoCheck));
-}
-
-TEST(OperatorsStrong, opor)
-{
-	Strong s(Strong::NoLog);
-
-	ASSERT_EQ(3, static_cast<int>((s | Strong::NoCheck)));
-}
-
-TEST(OperatorsStrong, opxor)
-{
-	Strong s(Strong::NoLog);
-
-	ASSERT_EQ(3, static_cast<int>((s ^ Strong::NoCheck)));
-}
-
-TEST(OperatorsStrong, opnot)
-{
-	Strong s(Strong::NoLog);
-
-	ASSERT_EQ(254, static_cast<int>(~s));
-}
-
-/* --------------------------------------------------------
- * Flags with standard enums
- * -------------------------------------------------------- */
-
-TEST(Standard, construct)
-{
-	Flags<Standard> s;
-
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-
-	Flags <Standard> s2(Fullscreen | Audio);
-
-	ASSERT_TRUE(s2);
-	ASSERT_FALSE(!s2);
-	ASSERT_TRUE(s2 & Fullscreen);
-	ASSERT_TRUE(s2 & Audio);
-	ASSERT_TRUE((s2 & Fullscreen) == Fullscreen);
-	ASSERT_TRUE((s2 & Audio) == Audio);
-	ASSERT_TRUE(s2 == (Audio | Fullscreen));
-}
-
-TEST(Standard, addByOne)
-{
-	Flags<Standard> s;
-
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-	ASSERT_TRUE(!(s & Fullscreen));
-	ASSERT_TRUE(!(s & Audio));
-
-	s |= Fullscreen;
-	ASSERT_TRUE(s);
-	ASSERT_FALSE(!s);
-	ASSERT_TRUE(s & Fullscreen);
-	ASSERT_TRUE((s & Fullscreen) == Fullscreen);
-	ASSERT_FALSE(s & Audio);
-	ASSERT_FALSE((s & Audio) == Audio);
-	ASSERT_TRUE(s == Fullscreen);
-
-	s |= Audio;
-	ASSERT_TRUE(s);
-	ASSERT_FALSE(!s);
-	ASSERT_TRUE(s & Fullscreen);
-	ASSERT_TRUE((s & Fullscreen) == Fullscreen);
-	ASSERT_TRUE(s & Audio);
-	ASSERT_TRUE((s & Audio) == Audio);
-	ASSERT_TRUE(s == (Fullscreen | Audio));
-}
-
-TEST(Standard, add)
-{
-	Flags<Standard> s;
-
-	s |= Fullscreen | Audio;
-	ASSERT_TRUE(s & (Fullscreen | Audio));
-	ASSERT_TRUE((s & (Fullscreen | Audio)) == (Fullscreen | Audio));
-}
-
-TEST(Standard, removeByOne)
-{
-	Flags<Standard> s(Fullscreen | Audio);
-
-	s &= ~(Fullscreen);
-	ASSERT_TRUE(s);
-	ASSERT_FALSE(!s);
-	ASSERT_FALSE(s & Fullscreen);
-	ASSERT_FALSE((s & Fullscreen) == Fullscreen);
-	ASSERT_TRUE(s & Audio);
-	ASSERT_TRUE((s & Audio) == Audio);
-
-	s &= ~(Audio);
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-}
-
-TEST(Standard, remove)
-{
-	Flags<Standard> s(Fullscreen | Audio);
-
-	s &= ~(Fullscreen | Audio);
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-}
-
-TEST(Standard, xorAdd)
-{
-	Flags<Standard> s(Fullscreen | Audio);
-
-	s ^= Audio;
-	ASSERT_TRUE(s & Fullscreen);
-	ASSERT_TRUE((s & Fullscreen) == Fullscreen);
-	ASSERT_FALSE(s & Audio);
-	ASSERT_FALSE((s & Audio) == Audio);
-}
-
-/* --------------------------------------------------------
- * Flags with strong enums
- * -------------------------------------------------------- */
-
-TEST(Strong, construct)
-{
-	Flags<Strong> s;
-
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-
-	Flags <Strong> s2(Strong::NoLog | Strong::NoCheck);
-
-	ASSERT_TRUE(s2);
-	ASSERT_FALSE(!s2);
-	ASSERT_TRUE(s2 & Strong::NoLog);
-	ASSERT_TRUE(s2 & Strong::NoCheck);
-	ASSERT_TRUE((s2 & Strong::NoLog) == Strong::NoLog);
-	ASSERT_TRUE((s2 & Strong::NoCheck) == Strong::NoCheck);
-	ASSERT_TRUE(s2 == (Strong::NoLog | Strong::NoCheck));
-}
-
-TEST(Strong, addByOne)
-{
-	Flags<Strong> s;
-
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-	ASSERT_TRUE(!(s & Strong::NoLog));
-	ASSERT_TRUE(!(s & Strong::NoCheck));
-
-	s |= Strong::NoLog;
-	ASSERT_TRUE(s);
-	ASSERT_FALSE(!s);
-	ASSERT_TRUE(s & Strong::NoLog);
-	ASSERT_TRUE((s & Strong::NoLog) == Strong::NoLog);
-	ASSERT_FALSE(s & Strong::NoCheck);
-	ASSERT_FALSE((s & Strong::NoCheck) == Strong::NoCheck);
-	ASSERT_TRUE(s == Strong::NoLog);
-
-	s |= Strong::NoCheck;
-	ASSERT_TRUE(s);
-	ASSERT_FALSE(!s);
-	ASSERT_TRUE(s & Strong::NoLog);
-	ASSERT_TRUE((s & Strong::NoLog) == Strong::NoLog);
-	ASSERT_TRUE(s & Strong::NoCheck);
-	ASSERT_TRUE((s & Strong::NoCheck) == Strong::NoCheck);
-	ASSERT_TRUE(s == (Strong::NoLog | Strong::NoCheck));
-}
-
-TEST(Strong, add)
-{
-	Flags<Strong> s;
-
-	s |= Strong::NoLog | Strong::NoCheck;
-	ASSERT_TRUE(s & (Strong::NoLog | Strong::NoCheck));
-	ASSERT_TRUE((s & (Strong::NoLog | Strong::NoCheck)) == (Strong::NoLog | Strong::NoCheck));
-}
-
-TEST(Strong, removeByOne)
-{
-	Flags<Strong> s(Strong::NoLog | Strong::NoCheck);
-
-	s &= ~(Strong::NoLog);
-	ASSERT_TRUE(s);
-	ASSERT_FALSE(!s);
-	ASSERT_FALSE(s & Strong::NoLog);
-	ASSERT_FALSE((s & Strong::NoLog) == Strong::NoLog);
-	ASSERT_TRUE(s & Strong::NoCheck);
-	ASSERT_TRUE((s & Strong::NoCheck) == Strong::NoCheck);
-
-	s &= ~(Strong::NoCheck);
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-}
-
-TEST(Strong, remove)
-{
-	Flags<Strong> s(Strong::NoLog | Strong::NoCheck);
-
-	s &= ~(Strong::NoLog | Strong::NoCheck);
-	ASSERT_FALSE(s);
-	ASSERT_TRUE(!s);
-}
-
-TEST(Strong, xorAdd)
-{
-	Flags<Strong> s(Strong::NoLog | Strong::NoCheck);
-
-	s ^= Strong::NoCheck;
-	ASSERT_TRUE(s & Strong::NoLog);
-	ASSERT_TRUE((s & Strong::NoLog) == Strong::NoLog);
-	ASSERT_FALSE(s & Strong::NoCheck);
-	ASSERT_FALSE((s & Strong::NoCheck) == Strong::NoCheck);
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
\ No newline at end of file
--- a/C++/Tests/Hash/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#
-# CMakeLists.txt -- tests for Hash
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-find_package(OpenSSL REQUIRED)
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Hash.cpp
-	${code_SOURCE_DIR}/C++/Hash.h
-	main.cpp
-)
-
-define_test(hash "${SOURCES}")
-
-target_include_directories(hash PRIVATE ${OPENSSL_INCLUDE_DIR})
-target_link_libraries(hash ${OPENSSL_LIBRARIES})
--- a/C++/Tests/Hash/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * main.cpp -- test the hash cryptographic functions
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <gtest/gtest.h>
-
-#include <Hash.h>
-
-/*
- * We test the "Hello World" message in all cryptographic functions.
- */
-
-TEST(Hash, md5)
-{
-	std::string expected = "b10a8db164e0754105b7a99be72e3fe5";
-	std::string output = Hash::md5("Hello World");
-
-	ASSERT_EQ(expected, output);
-}
-
-TEST(Hash, sha1)
-{
-	std::string expected = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
-	std::string output = Hash::sha1("Hello World");
-
-	ASSERT_EQ(expected, output);
-}
-
-TEST(Hash, sha256)
-{
-	std::string expected = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e";
-	std::string output = Hash::sha256("Hello World");
-
-	ASSERT_EQ(expected, output);
-}
-
-TEST(Hash, sha512)
-{
-	std::string expected = "2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b";
-	std::string output = Hash::sha512("Hello World");
-
-	ASSERT_EQ(expected, output);
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Ini/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#
-# CMakeLists.txt -- tests for Ini
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Ini.cpp
-	${code_SOURCE_DIR}/C++/Ini.h
-	main.cpp
-	configs/simple.conf
-	configs/multi.conf
-	configs/novalue.conf
-	configs/compact.conf
-	configs/includes.conf
-	configs/error-badcomment.conf
-	configs/error-lineassigment.conf
-	configs/error-nosection.conf
-)
-
-define_test(ini "${SOURCES}")
-
-add_custom_command(
-	TARGET ini
-	POST_BUILD
-	COMMENT "Copying examples files"
-	COMMAND
-		${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/configs $<TARGET_FILE_DIR:ini>
-)
--- a/C++/Tests/Ini/configs/compact.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[general]verbose=true foreground=false[server]host=google.fr
--- a/C++/Tests/Ini/configs/error-badcomment.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-[general]
-verbose #hello = xyz
--- a/C++/Tests/Ini/configs/error-badsection.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-[[general]
-verbose = false
--- a/C++/Tests/Ini/configs/error-lineassigment.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-[general]
-host
-=
-google.fr
--- a/C++/Tests/Ini/configs/error-nosection.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-option = value
--- a/C++/Tests/Ini/configs/includes.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# With some includes
-@include "simple.conf"	# comments also work here
-
-[standard]
-verbose = false
--- a/C++/Tests/Ini/configs/multi.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-[entity]
-name	= "Player"
-version	= 1.0
-
-[entity]
-name	= "Subwinner"
-version	= 2.0
\ No newline at end of file
--- a/C++/Tests/Ini/configs/novalue.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-[plugins]
-histedit=
-highlight= #empty
-general = 
-
-
--- a/C++/Tests/Ini/configs/simple.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-[general]
-option1=1
-option2 =2
-option3 = 3
--- a/C++/Tests/Ini/configs/tokens.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-[tokens]
-bracket = "I have [brackets]"
-at = "I have foo@at"
--- a/C++/Tests/Ini/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,251 +0,0 @@
-/*
- * main.cpp -- main test file for Ini
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <Ini.h>
-
-class BasicTest : public testing::Test {
-protected:
-	Ini m_ini;
-
-public:
-	BasicTest()
-		: m_ini("simple.conf")
-	{
-	}
-
-};
-
-TEST_F(BasicTest, simple)
-{
-	ASSERT_EQ(1, static_cast<int>(m_ini.size()));
-}
-
-TEST_F(BasicTest, iniOperators)
-{
-	try {
-		ASSERT_EQ(3, static_cast<int>(m_ini[0].size()));
-		ASSERT_EQ("general", m_ini[0].key());
-		ASSERT_EQ("general", m_ini["general"].key());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST_F(BasicTest, iniSectionOperators)
-{
-	try {
-		// option1=1 (indexes)
-		ASSERT_EQ("option1", m_ini[0][0].key());
-		ASSERT_EQ("1", m_ini[0][0].value());
-
-		// option1=1 (keys)
-		ASSERT_EQ("option1", m_ini["general"]["option1"].key());
-		ASSERT_EQ("1", m_ini["general"]["option1"].value());
-
-		// option2 =2 (indexes)
-		ASSERT_EQ("option2", m_ini[0][1].key());
-		ASSERT_EQ("2", m_ini[0][1].value());
-
-		// option2 =2 (keys)
-		ASSERT_EQ("option2", m_ini["general"]["option2"].key());
-		ASSERT_EQ("2", m_ini["general"]["option2"].value());
-
-		// option3 = 3 (indexes)
-		ASSERT_EQ("option3", m_ini[0][2].key());
-		ASSERT_EQ("3", m_ini[0][2].value());
-
-		// option3 = 3 (keys)
-		ASSERT_EQ("option3", m_ini["general"]["option3"].key());
-		ASSERT_EQ("3", m_ini["general"]["option3"].value());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Reserved tokens in words
- * -------------------------------------------------------- */
-
-TEST(Tokens, iniReserved)
-{
-	try {
-		Ini ini("tokens.conf");
-
-		ASSERT_EQ("I have [brackets]", ini["tokens"]["bracket"].value());
-		ASSERT_EQ("I have foo@at", ini["tokens"]["at"].value());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Multiple definition
- * -------------------------------------------------------- */
-
-class MultiTest : public testing::Test {
-protected:
-	Ini m_ini;
-
-public:
-	MultiTest()
-		: m_ini("multi.conf")
-	{
-	}
-};
-
-TEST_F(MultiTest, defined)
-{
-	ASSERT_EQ(2, static_cast<int>(m_ini.size()));
-	ASSERT_EQ("name", m_ini[0]["name"].key());
-	ASSERT_EQ("Player", m_ini[0]["name"].value());
-	ASSERT_EQ("version", m_ini[0]["version"].key());
-	ASSERT_EQ("1.0", m_ini[0]["version"].value());
-	ASSERT_EQ("name", m_ini[1]["name"].key());
-	ASSERT_EQ("Subwinner", m_ini[1]["name"].value());
-	ASSERT_EQ("version", m_ini[1]["version"].key());
-	ASSERT_EQ("2.0", m_ini[1]["version"].value());
-}
-
-/* --------------------------------------------------------
- * Option with no values
- * -------------------------------------------------------- */
-
-class NoValueTest : public testing::Test {
-protected:
-	Ini m_ini;
-
-public:
-	NoValueTest()
-		: m_ini("novalue.conf")
-	{
-	}
-};
-
-TEST_F(NoValueTest, isDefined)
-{
-	ASSERT_EQ("plugins", m_ini[0].key());
-	ASSERT_EQ("", m_ini["plugins"]["histedit"].value());
-	ASSERT_EQ("", m_ini["plugins"]["highlight"].value());
-	ASSERT_EQ("", m_ini["plugins"]["general"].value());
-}
-
-/* --------------------------------------------------------
- * Include tests
- * -------------------------------------------------------- */
-
-class IncludeTest : public testing::Test {
-protected:
-	Ini m_ini;
-
-public:
-	IncludeTest()
-		: m_ini("includes.conf")
-	{
-	}
-};
-
-TEST_F(IncludeTest, all)
-{
-	ASSERT_EQ(2, static_cast<int>(m_ini.size()));
-
-	// from include
-	ASSERT_EQ("1", m_ini[0][0].value());
-	ASSERT_EQ("2", m_ini[0][1].value());
-	ASSERT_EQ("3", m_ini[0][2].value());
-
-	// from standard
-	ASSERT_EQ("false", m_ini[1][0].value());
-}
-
-/* --------------------------------------------------------
- * Compact
- * -------------------------------------------------------- */
-
-TEST(Compact, test)
-{
-	try {
-		Ini ini("compact.conf");
-
-		ASSERT_EQ(2, static_cast<int>(ini.size()));
-		ASSERT_EQ("true", ini["general"]["verbose"].value());
-		ASSERT_EQ("false", ini["general"]["foreground"].value());
-		ASSERT_EQ("google.fr", ini["server"]["host"].value());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Errors
- * -------------------------------------------------------- */
-
-TEST(Errors, nosection)
-{
-	// An option outside a section is not allowed
-	try {
-		Ini ini("error-nosection.conf");
-
-		FAIL() << "Failure expected, got success";
-	} catch (const std::exception &ex) {
-	}
-}
-
-TEST(Errors, lineassigment)
-{
-	// The = assignment must be on the same line as the option key
-	try {
-		Ini ini("error-lineassigment.conf");
-
-		FAIL() << "Failure expected, got success";
-	} catch (const std::exception &ex) {
-	}
-}
-
-TEST(Errors, badcomment)
-{
-	// Comment can't between option-key and = assigment
-	try {
-		Ini ini("error-badcomment.conf");
-
-		FAIL() << "Failure expected, got success";
-	} catch (const std::exception &ex) {
-	}
-}
-
-TEST(Errors, badsection)
-{
-	// Bad section naming
-	try {
-		Ini ini("error-badsection.conf");
-
-		FAIL() << "Failure expected, got success";
-	} catch (const std::exception &ex) {
-		std::cout << ex.what() << std::endl;
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Json/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#
-# CMakeLists.txt -- tests for Json
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(json)
-
-find_package(Jansson REQUIRED)
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Json.cpp
-	${code_SOURCE_DIR}/C++/Json.h
-	${json_SOURCE_DIR}/data/array.json
-	${json_SOURCE_DIR}/data/array-all.json
-	${json_SOURCE_DIR}/data/object.json
-	${json_SOURCE_DIR}/data/object-all.json
-	${json_SOURCE_DIR}/data/simple.json
-	main.cpp
-)
-
-define_test(json "${SOURCES}")
-
-target_include_directories(json PRIVATE ${Jansson_INCLUDE_DIRS})
-target_link_libraries(json ${Jansson_LIBRARIES})
-target_compile_definitions(json PRIVATE "BINARY=\"${json_BINARY_DIR}\"" "SOURCE=\"${json_SOURCE_DIR}\"")
--- a/C++/Tests/Json/data/array-all.json	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-[
-    123,
-    9.2,
-    false,
-    true,
-    null,
-    {},
-    []
-]
--- a/C++/Tests/Json/data/array.json	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[1, 2, 3]
--- a/C++/Tests/Json/data/object-all.json	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-{
-    "integer": 123,
-    "real": 9.2,
-    "false": false,
-    "true": true,
-    "null": null,
-    "object": {},
-    "array": []
-}
--- a/C++/Tests/Json/data/object.json	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-{
-    "name": "simple",
-    "description": "basic JSON file"
-}
--- a/C++/Tests/Json/data/simple.json	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-{
-}
--- a/C++/Tests/Json/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,877 +0,0 @@
-/*
- * main.cpp -- test the jansson wrapper
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <set>
-#include <unordered_map>
-
-#include <gtest/gtest.h>
-
-#include "Json.h"
-
-/* --------------------------------------------------------
- * Miscellaneous
- * -------------------------------------------------------- */
-
-TEST(Misc, copy)
-{
-	JsonObject object;
-
-	object.set("integer", 123);
-	object.set("true", true);
-
-	JsonObject object2{object};
-
-	ASSERT_TRUE(object2.isObject());
-	ASSERT_EQ(123, object2["integer"].toInteger());
-	ASSERT_TRUE(object2["true"].isTrue());
-}
-
-TEST(Misc, copyAssign)
-{
-	JsonObject object;
-
-	{
-		JsonObject tmp;
-
-		tmp.set("integer", 123);
-		tmp.set("true", true);
-
-		object = tmp;
-	}
-
-	ASSERT_TRUE(object.isObject());
-	ASSERT_EQ(123, object["integer"].toInteger());
-	ASSERT_TRUE(object["true"].isTrue());
-}
-
-TEST(Misc, move)
-{
-	JsonObject object(123);
-	JsonObject object2(std::move(object));
-
-	ASSERT_TRUE(object.isNull());
-	ASSERT_TRUE(object2.isInteger());
-	ASSERT_EQ(123, object2.toInteger());
-}
-
-TEST(Misc, moveAssign)
-{
-	JsonObject object(123);
-	JsonObject object2;
-
-	object2 = std::move(object);
-
-	ASSERT_TRUE(object.isNull());
-	ASSERT_TRUE(object2.isInteger());
-	ASSERT_EQ(123, object2.toInteger());
-}
-
-/* --------------------------------------------------------
- * JsonValue constructors
- * -------------------------------------------------------- */
-
-TEST(Constructors, null)
-{
-	try {
-		JsonValue value;
-
-		ASSERT_TRUE(value.isNull());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Constructors, boolean)
-{
-	try {
-		JsonValue value{true};
-
-		ASSERT_TRUE(value.isTrue());
-		ASSERT_TRUE(value.isBoolean());
-		ASSERT_FALSE(value.isFalse());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Constructors, integer)
-{
-	try {
-		JsonValue value{123};
-
-		ASSERT_TRUE(value.isInteger());
-		ASSERT_TRUE(value.isNumber());
-		ASSERT_FALSE(value.isReal());
-		ASSERT_EQ(123, value.toInteger());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Constructors, real)
-{
-	try {
-		JsonValue value{9.2};
-
-		ASSERT_TRUE(value.isReal());
-		ASSERT_TRUE(value.isNumber());
-		ASSERT_FALSE(value.isInteger());
-		ASSERT_EQ(9.2, value.toReal());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Constructors, string)
-{
-	try {
-		JsonValue value("hello");
-
-		ASSERT_TRUE(value.isString());
-		ASSERT_EQ("hello", value.toString());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Object
- * -------------------------------------------------------- */
-
-TEST(Object, set)
-{
-	try {
-		JsonObject object;
-
-		object.set("integer", 123);
-		object.set("string", "hello");
-		object.set("true", true);
-
-		ASSERT_EQ(123, object["integer"].toInteger());
-		ASSERT_EQ("hello", object["string"].toString());
-		ASSERT_TRUE(object["true"].isTrue());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Object, clear)
-{
-	try {
-		JsonObject object;
-
-		object.set("integer", 123);
-		object.set("string", "hello");
-		object.set("true", true);
-
-		object.clear();
-
-		ASSERT_EQ(0, static_cast<int>(object.size()));
-		ASSERT_FALSE(object.contains("integer"));
-		ASSERT_FALSE(object.contains("string"));
-		ASSERT_FALSE(object.contains("true"));
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Object, erase)
-{
-	try {
-		JsonObject object;
-
-		object.set("integer", 123);
-		object.set("string", "hello");
-		object.set("true", true);
-
-		object.erase("integer");
-
-		ASSERT_EQ(2, static_cast<int>(object.size()));
-		ASSERT_FALSE(object.contains("integer"));
-		ASSERT_TRUE(object.contains("string"));
-		ASSERT_TRUE(object.contains("true"));
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(ObjectInitializer, simple)
-{
-	try {
-		JsonObject object{
-			{ "username", "jean" },
-			{ "age", 99 }
-		};
-
-		ASSERT_EQ(2, static_cast<int>(object.size()));
-		ASSERT_EQ("jean", object["username"].toString());
-		ASSERT_EQ(99, object["age"].toInteger());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(ObjectInitializer, deep)
-{
-	try {
-		JsonObject object{
-			{ "username", "jean"		},
-			{ "age", 99			},
-			{ "network", JsonObject{
-					{ "port", 9999 		},
-					{ "host", "localhost"	}
-				}
-			}
-		};
-
-		// First
-		ASSERT_EQ(3, static_cast<int>(object.size()));
-		ASSERT_EQ("jean", object["username"].toString());
-		ASSERT_EQ(99, object["age"].toInteger());
-
-		// Second
-		JsonObject network = object["network"].toObject();
-		ASSERT_TRUE(network.isObject());
-		ASSERT_EQ(2, static_cast<int>(network.size()));
-		ASSERT_EQ(9999, network["port"].toInteger());
-		ASSERT_EQ("localhost", network["host"].toString());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Array
- * -------------------------------------------------------- */
-
-TEST(Array, push)
-{
-	try {
-		JsonArray array;
-
-		ASSERT_TRUE(array.isArray());
-
-		array.push(1);
-		array.push("hello");
-		array.push(true);
-
-		ASSERT_EQ(3, static_cast<int>(array.size()));
-		ASSERT_TRUE(array[0].isTrue());
-		ASSERT_EQ("hello", array[1].toString());
-		ASSERT_EQ(1, array[2].toInteger());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Array, append)
-{
-	try {
-		JsonArray array;
-
-		ASSERT_TRUE(array.isArray());
-
-		array.append(1);
-		array.append("hello");
-		array.append(true);
-
-		ASSERT_EQ(3, static_cast<int>(array.size()));
-		ASSERT_EQ(1, array[0].toInteger());
-		ASSERT_EQ("hello", array[1].toString());
-		ASSERT_TRUE(array[2].isTrue());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Array, insert)
-{
-	try {
-		JsonArray array;
-
-		ASSERT_TRUE(array.isArray());
-
-		array.insert(1, 0);
-		array.insert("hello", 1);
-		array.insert(true, 0);
-
-		ASSERT_EQ(3, static_cast<int>(array.size()));
-		ASSERT_TRUE(array[0].isTrue());
-		ASSERT_EQ(1, array[1].toInteger());
-		ASSERT_EQ("hello", array[2].toString());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Array, clear)
-{
-	try {
-		JsonArray array;
-
-		array.append(1);
-		array.append("hello");
-		array.append(true);
-
-		array.clear();
-
-		ASSERT_EQ(0, static_cast<int>(array.size()));
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Array, erase)
-{
-	try {
-		JsonArray array;
-
-		array.append(1);
-		array.append("hello");
-		array.append(true);
-
-		array.erase(0);
-
-		ASSERT_EQ(2, static_cast<int>(array.size()));
-		ASSERT_EQ("hello", array[0].toString());
-		ASSERT_TRUE(array[1].isTrue());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Array, eraseIterator)
-{
-	try {
-		JsonArray array;
-
-		array.append(1);
-		array.append("hello");
-		array.append(true);
-
-		array.erase(array.begin());
-
-		ASSERT_EQ(2, static_cast<int>(array.size()));
-		ASSERT_EQ("hello", array[0].toString());
-		ASSERT_TRUE(array[1].isTrue());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Array, eraseConstIterator)
-{
-	try {
-		JsonArray array;
-
-		array.append(1);
-		array.append("hello");
-		array.append(true);
-
-		array.erase(array.cbegin());
-
-		ASSERT_EQ(2, static_cast<int>(array.size()));
-		ASSERT_EQ("hello", array[0].toString());
-		ASSERT_TRUE(array[1].isTrue());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(ArrayInitializer, simple)
-{
-	try {
-		JsonArray array{123, true, "hello"};
-
-		ASSERT_EQ(3, static_cast<int>(array.size()));
-		ASSERT_EQ(123, array[0].toInteger());
-		ASSERT_TRUE(array[1].isTrue());
-		ASSERT_EQ("hello", array[2].toString());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(ArrayInitializer, deep)
-{
-	try {
-		JsonArray array{
-			123,
-			true,
-			"hello",
-			JsonArray{
-				321,
-				false,
-				"olleh"
-			}
-		};
-
-		// First
-		ASSERT_EQ(4, static_cast<int>(array.size()));
-		ASSERT_EQ(123, array[0].toInteger());
-		ASSERT_TRUE(array[1].isTrue());
-		ASSERT_EQ("hello", array[2].toString());
-
-		// Second
-		JsonArray array2 = array[3].toArray();
-		ASSERT_TRUE(array.isArray());
-		ASSERT_EQ(3, static_cast<int>(array2.size()));
-		ASSERT_EQ(321, array2[0].toInteger());
-		ASSERT_TRUE(array2[1].isFalse());
-		ASSERT_EQ("olleh", array2[2].toString());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * I/O
- * -------------------------------------------------------- */
-
-TEST(FileRead, simple)
-{
-	try {
-		JsonDocument doc(std::ifstream(SOURCE "/data/simple.json"));
-
-		ASSERT_TRUE(doc.isObject());
-		ASSERT_FALSE(doc.isArray());
-
-		JsonObject object = doc.toObject();
-		JsonArray array = doc.toArray();
-
-		ASSERT_TRUE(object.isObject());
-		ASSERT_FALSE(array.isArray());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(FileRead, fail)
-{
-	try {
-		JsonDocument(std::ifstream(SOURCE "/data/notexist.json"));
-
-		FAIL() << "Exception expected";
-	} catch (const JsonError &) {
-	}
-}
-
-TEST(FileWrite, simple)
-{
-	try {
-		JsonObject object{
-			{ "name", "jean" },
-			{ "age", 99 }
-		};
-
-		object.write(std::ofstream(BINARY "/object-write.json"));
-
-		JsonObject object2 = JsonDocument(std::ifstream(BINARY "/object-write.json")).toObject();
-
-		ASSERT_EQ(object2, object);
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(StringRead, simple)
-{
-	try {
-		JsonDocument doc("{ \"license\": \"ISC\" }");
-
-		ASSERT_TRUE(doc.isObject());
-		ASSERT_FALSE(doc.isArray());
-
-		JsonObject object = doc.toObject();
-		JsonArray array = doc.toArray();
-
-		ASSERT_TRUE(object.isObject());
-		ASSERT_FALSE(array.isArray());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(StringRead, fail)
-{
-	try {
-		JsonDocument("{ \"license\": ISC }");
-
-		FAIL() << "Exception expected";
-	} catch (const JsonError &ex) {
-	}
-}
-
-TEST(StringWrite, simple)
-{
-	try {
-		JsonObject object{
-			{ "name", "jean" },
-			{ "age", 99 }
-		};
-
-		JsonObject object2 = JsonDocument(object.dump()).toObject();
-
-		ASSERT_EQ(object2, object);
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Object read
- * -------------------------------------------------------- */
-
-class ObjectRead : public testing::Test {
-protected:
-	JsonObject m_object;
-	JsonObject m_objectAll;
-
-public:
-	ObjectRead()
-	{
-		m_object = JsonDocument(std::ifstream(SOURCE "/data/object.json")).toObject();
-		m_objectAll = JsonDocument(std::ifstream(SOURCE "/data/object-all.json")).toObject();
-	}
-};
-
-TEST_F(ObjectRead, simple)
-{
-	try {
-		JsonValue name = m_object["name"];
-		JsonValue description = m_object["description"];
-
-		ASSERT_TRUE(name.isString());
-		ASSERT_TRUE(description.isString());
-		ASSERT_EQ("simple", name.toString());
-		ASSERT_EQ("basic JSON file", description.toString());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST_F(ObjectRead, all)
-{
-	try {
-		ASSERT_TRUE(m_objectAll.contains("integer"));
-		ASSERT_FALSE(m_objectAll.contains("unexistant"));
-
-		ASSERT_TRUE(m_objectAll["integer"].isInteger());
-		ASSERT_TRUE(m_objectAll["integer"].isNumber());
-		ASSERT_EQ(123, m_objectAll["integer"].toInteger());
-
-		ASSERT_TRUE(m_objectAll["real"].isReal());
-		ASSERT_TRUE(m_objectAll["real"].isNumber());
-		ASSERT_EQ(9.2, m_objectAll["real"].toReal());
-
-		ASSERT_TRUE(m_objectAll["false"].isBoolean());
-		ASSERT_TRUE(m_objectAll["false"].isFalse());
-		ASSERT_FALSE(m_objectAll["false"].isTrue());
-
-		ASSERT_TRUE(m_objectAll["true"].isBoolean());
-		ASSERT_TRUE(m_objectAll["true"].isTrue());
-		ASSERT_FALSE(m_objectAll["true"].isFalse());
-
-		ASSERT_TRUE(m_objectAll["null"].isNull());
-
-		ASSERT_TRUE(m_objectAll["object"].isObject());
-		ASSERT_TRUE(m_objectAll["array"].isArray());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Array read
- * -------------------------------------------------------- */
-
-class ArrayRead : public testing::Test {
-protected:
-	JsonArray m_array;
-	JsonArray m_arrayAll;
-
-public:
-	ArrayRead()
-	{
-		m_array = JsonDocument(std::ifstream(SOURCE "/data/array.json")).toArray();
-		m_arrayAll = JsonDocument(std::ifstream(SOURCE "/data/array-all.json")).toArray();
-	}
-};
-
-TEST_F(ArrayRead, simple)
-{
-	try {
-		ASSERT_EQ(3, static_cast<int>(m_array.size()));
-		ASSERT_EQ(1, m_array[0].toInteger());
-		ASSERT_EQ(2, m_array[1].toInteger());
-		ASSERT_EQ(3, m_array[2].toInteger());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST_F(ArrayRead, all)
-{
-	try {
-		ASSERT_TRUE(m_arrayAll[0].isInteger());
-		ASSERT_TRUE(m_arrayAll[0].isNumber());
-		ASSERT_EQ(123, m_arrayAll[0].toInteger());
-
-		ASSERT_TRUE(m_arrayAll[1].isReal());
-		ASSERT_TRUE(m_arrayAll[1].isNumber());
-		ASSERT_EQ(9.2, m_arrayAll[1].toReal());
-
-		ASSERT_TRUE(m_arrayAll[2].isBoolean());
-		ASSERT_TRUE(m_arrayAll[2].isFalse());
-		ASSERT_FALSE(m_arrayAll[2].isTrue());
-
-		ASSERT_TRUE(m_arrayAll[3].isBoolean());
-		ASSERT_TRUE(m_arrayAll[3].isTrue());
-		ASSERT_FALSE(m_arrayAll[3].isFalse());
-
-		ASSERT_TRUE(m_arrayAll[4].isNull());
-
-		ASSERT_TRUE(m_arrayAll[5].isObject());
-		ASSERT_TRUE(m_arrayAll[6].isArray());
-	} catch (const JsonError &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Object iterators
- * -------------------------------------------------------- */
-
-class ObjectIteratorsTest : public testing::Test {
-protected:
-	JsonObject m_object;
-
-public:
-	ObjectIteratorsTest()
-	{
-		m_object.set("integer", 1);
-		m_object.set("string", "hello");
-		m_object.set("boolean", true);
-	}
-};
-
-TEST_F(ObjectIteratorsTest, operators)
-{
-	// Read only (non const)
-	{
-		std::set<std::string> expected{"boolean", "integer", "string"};
-		std::set<std::string> result;
-		std::unordered_map<std::string, JsonValue> values;
-		JsonObject::iterator it = m_object.begin();
-		JsonObject::iterator end = m_object.end();
-
-		while (it != end) {
-			values.insert({it->first, it->second});
-			result.insert((*it++).first);
-		}
-
-		ASSERT_EQ(expected, result);
-		ASSERT_EQ(1, values["integer"].toInteger());
-		ASSERT_EQ("hello", values["string"].toString());
-		ASSERT_TRUE(values["boolean"].isTrue());
-	}
-
-	// Read only (const)
-	{
-		std::set<std::string> expected{"boolean", "integer", "string"};
-		std::set<std::string> result;
-		std::unordered_map<std::string, JsonValue> values;
-		JsonObject::const_iterator it = m_object.cbegin();
-		JsonObject::const_iterator end = m_object.cend();
-
-		while (it != end) {
-			values.insert({it->first, it->second});
-			result.insert((*it++).first);
-		}
-
-		ASSERT_EQ(expected, result);
-		ASSERT_EQ(1, values["integer"].toInteger());
-		ASSERT_EQ("hello", values["string"].toString());
-		ASSERT_TRUE(values["boolean"].isTrue());
-	}
-}
-
-TEST_F(ObjectIteratorsTest, assign)
-{
-	// Assign (non const)
-	{
-		JsonObject::iterator it = m_object.begin();
-		std::string key = it->first;
-
-		it->second = JsonValue("CHANGED");
-
-		ASSERT_EQ("CHANGED", m_object[key].toString());
-		ASSERT_EQ("CHANGED", it->second.toString());
-		ASSERT_EQ(3, static_cast<int>(m_object.size()));
-	}
-}
-
-TEST_F(ObjectIteratorsTest, assignConst)
-{
-	// Assign (const)
-	{
-		JsonObject::const_iterator it = m_object.cbegin();
-		std::string key = it->first;
-		JsonValue orig = it->second;
-
-		it->second = JsonValue("CHANGED");
-
-		ASSERT_TRUE(m_object.contains(key));
-		ASSERT_EQ(orig, m_object[key]);
-		ASSERT_EQ(3, static_cast<int>(m_object.size()));
-	}
-}
-
-/* --------------------------------------------------------
- * Array iterators
- * -------------------------------------------------------- */
-
-class ArrayIteratorsTest : public testing::Test {
-protected:
-	JsonArray m_array;
-
-public:
-	ArrayIteratorsTest()
-	{
-		m_array.append(1);
-		m_array.append("hello");
-		m_array.append(true);
-	}
-};
-
-TEST_F(ArrayIteratorsTest, operators)
-{
-	// Read only (non const)
-	{
-		JsonArray::iterator it = m_array.begin();
-
-		ASSERT_EQ(1, (*it).toInteger());
-		ASSERT_EQ(1, it->toInteger());
-		ASSERT_EQ("hello", it[1].toString());
-		ASSERT_TRUE(it[2].isTrue());
-
-		JsonArray::iterator it2 = it + 1;
-		ASSERT_EQ(1, it2[-1].toInteger());
-		ASSERT_EQ("hello", it2->toString());
-		ASSERT_TRUE(it2[1].isTrue());
-
-		JsonArray::iterator it3 = it;
-		ASSERT_TRUE(it2 != it);
-		ASSERT_FALSE(it3 != it);
-
-		ASSERT_FALSE(it2 == it);
-		ASSERT_TRUE(it3 == it);
-
-		ASSERT_TRUE(it3 >= it);
-		ASSERT_TRUE(it2 >= it);
-
-		ASSERT_TRUE(it2 > it);
-		ASSERT_FALSE(it3 > it);
-
-		ASSERT_FALSE(it2 <= it);
-		ASSERT_TRUE(it3 <= it);
-
-		ASSERT_FALSE(it2 < it);
-		ASSERT_FALSE(it3 < it);
-	}
-
-	// Read only (const)
-	{
-		JsonArray::const_iterator it = m_array.cbegin();
-
-		ASSERT_EQ(1, (*it).toInteger());
-		ASSERT_EQ(1, it->toInteger());
-		ASSERT_EQ("hello", it[1].toString());
-		ASSERT_TRUE(it[2].isTrue());
-
-		JsonArray::const_iterator it2 = it + 1;
-		ASSERT_EQ(1, it2[-1].toInteger());
-		ASSERT_EQ("hello", it2->toString());
-		ASSERT_TRUE(it2[1].isTrue());
-
-		JsonArray::const_iterator it3 = it;
-		ASSERT_TRUE(it2 != it);
-		ASSERT_FALSE(it3 != it);
-
-		ASSERT_FALSE(it2 == it);
-		ASSERT_TRUE(it3 == it);
-
-		ASSERT_TRUE(it3 >= it);
-		ASSERT_TRUE(it2 >= it);
-
-		ASSERT_TRUE(it2 > it);
-		ASSERT_FALSE(it3 > it);
-
-		ASSERT_FALSE(it2 <= it);
-		ASSERT_TRUE(it3 <= it);
-
-		ASSERT_FALSE(it2 < it);
-		ASSERT_FALSE(it3 < it);
-	}
-}
-
-TEST_F(ArrayIteratorsTest, assign)
-{
-	// Assign (non const)
-	{
-		JsonArray::iterator it = m_array.begin();
-
-		*it = JsonValue(9999);
-
-		ASSERT_EQ(3, static_cast<int>(m_array.size()));
-		ASSERT_EQ(9999, it->toInteger());
-		ASSERT_EQ(9999, m_array[0].toInteger());
-	}
-}
-
-TEST_F(ArrayIteratorsTest, assignConst)
-{
-	// Assign (const)
-	{
-		JsonArray::const_iterator it = m_array.cbegin();
-
-		*it = JsonValue(9999);
-
-		ASSERT_EQ(3, static_cast<int>(m_array.size()));
-		ASSERT_EQ(1, it->toInteger());
-		ASSERT_EQ(1, m_array[0].toInteger());
-	}
-}
-
-TEST_F(ArrayIteratorsTest, castToRef)
-{
-	JsonArray array{1, 2, 3};
-	int i = 1;
-
-	for (const JsonValue &v : array)
-	{
-		ASSERT_EQ(i++, v.toInteger());
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/OptionParser/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- tests for OptionParser
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/OptionParser.cpp
-	${code_SOURCE_DIR}/C++/OptionParser.h
-	main.cpp
-)
-
-define_test(optionparser "${SOURCES}")
--- a/C++/Tests/OptionParser/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
- * main.cpp -- main test file for OptionParser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <gtest/gtest.h>
-
-#include <OptionParser.h>
-
-/* --------------------------------------------------------
- * Short options
- * -------------------------------------------------------- */
-
-TEST(Short, simpleNoArg)
-{
-	OptionParser parser{
-		{ "a", "",	Option::NoArg	},
-		{ "b", "",	Option::NoArg	}
-	};
-
-	OptionPack pack = parser.parse({ "-a", "-b" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(2, static_cast<int>(pack.size()));
-	ASSERT_EQ(2, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "a");
-	ASSERT_TRUE(pack[1] == "b");
-}
-
-TEST(Short, simpleArg)
-{
-	OptionParser parser{
-		{ "v", "",	Option::NoArg	},
-		{ "c", "",			}
-	};
-
-	OptionPack pack = parser.parse({ "-v", "-cfoo.conf" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(2, static_cast<int>(pack.size()));
-	ASSERT_EQ(2, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "v");
-	ASSERT_TRUE(pack[1] == "c");
-	ASSERT_EQ("foo.conf", pack[1].value());
-}
-
-TEST(Short, spacedArg)
-{
-	OptionParser parser{
-		{ "v", "",	Option::NoArg	},
-		{ "c", "",			}
-	};
-
-	OptionPack pack = parser.parse({ "-v", "-c", "foo.conf" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(2, static_cast<int>(pack.size()));
-	ASSERT_EQ(3, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "v");
-	ASSERT_TRUE(pack[1] == "c");
-	ASSERT_EQ("foo.conf", pack[1].value());
-}
-
-TEST(Short, compacted)
-{
-	OptionParser parser{
-		{ "a", "",	Option::NoArg	},
-		{ "b", "",	Option::NoArg	},
-		{ "c", "",	Option::NoArg	},
-	};
-
-	OptionPack pack = parser.parse({ "-abc" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(3, static_cast<int>(pack.size()));
-	ASSERT_EQ(1, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "a");
-	ASSERT_TRUE(pack[1] == "b");
-	ASSERT_TRUE(pack[2] == "c");
-}
-
-TEST(Short, compactedArg)
-{
-	OptionParser parser{
-		{ "a", "",			},
-		{ "b", "",			},
-		{ "c", "",			},
-	};
-
-	OptionPack pack = parser.parse({ "-abc" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(1, static_cast<int>(pack.size()));
-	ASSERT_EQ(1, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "a");
-}
-
-/* --------------------------------------------------------
- * Long options
- * -------------------------------------------------------- */
-
-TEST(Long, simple)
-{
-	OptionParser parser{
-		{ "",	"verbose",	Option::NoArg	},
-		{ "",	"fullscreen",	Option::NoArg	}
-	};
-
-	OptionPack pack = parser.parse({ "--fullscreen" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(1, static_cast<int>(pack.size()));
-	ASSERT_EQ(1, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "fullscreen");
-}
-
-TEST(Long, simpleArg)
-{
-	OptionParser parser{
-		{ "", "config",			},
-		{ "", "level",			}
-	};
-
-	OptionPack pack = parser.parse({ "--config", "config.conf", "--level", "2" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(2, static_cast<int>(pack.size()));
-	ASSERT_EQ(4, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "config");
-	ASSERT_EQ("config.conf", pack[0].value());
-	ASSERT_TRUE(pack[1] == "level");
-	ASSERT_EQ("2", pack[1].value());
-}
-
-/* --------------------------------------------------------
- * Combined
- * -------------------------------------------------------- */
-
-TEST(Combined, simple)
-{
-	OptionParser parser{
-		{ "v", "verbose",	Option::NoArg	},
-		{ "l", "level",		Option::NoArg	}
-	};
-
-	OptionPack pack = parser.parse({ "-v", "-l", "--verbose", "--level" });
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_TRUE(pack[0] == "v" && pack[0] == "verbose");
-	ASSERT_TRUE(pack[1] == "l" && pack[1] == "level");
-	ASSERT_TRUE(pack[2] == "v" && pack[2] == "verbose");
-	ASSERT_TRUE(pack[3] == "l" && pack[3] == "level");
-}
-
-/* --------------------------------------------------------
- * Flags
- * -------------------------------------------------------- */
-
-TEST(Flags, standard)
-{
-	// No flags, parse unless there is an argument which is not an option
-	OptionParser parser{
-		{ "v", "",		Option::NoArg	}
-	};
-
-	OptionPack pack = parser.parse({ "-v", "install", "malikania" });
-
-	ASSERT_FALSE(pack);
-
-	ASSERT_EQ(1, static_cast<int>(pack.size()));
-	ASSERT_EQ(1, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "v");
-}
-
-TEST(Flags, unstrict)
-{
-	// No flags, parse unless there is an argument which is not an option
-	OptionParser parser{
-		{ "v", "",		Option::NoArg	},
-		{ "d", "",				}
-	};
-
-	OptionPack pack = parser.parse({ "-v", "install", "malikania", "-d", "/usr/local" }, OptionParser::Unstrict);
-
-	ASSERT_TRUE(pack);
-
-	ASSERT_EQ(2, static_cast<int>(pack.size()));
-	ASSERT_EQ(5, pack.parsed());
-
-	ASSERT_TRUE(pack[0] == "v");
-	ASSERT_TRUE(pack[1] == "d");
-	ASSERT_EQ("/usr/local", pack[1].value());
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Pack/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- tests for Pack
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Pack.cpp
-	${code_SOURCE_DIR}/C++/Pack.h
-	main.cpp
-)
-
-define_test(pack "${SOURCES}")
--- a/C++/Tests/Pack/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,508 +0,0 @@
-/*
- * TestPack.cpp -- test the pack serializer
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sstream>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <Pack.h>
-
-struct Point
-{
-	uint32_t width{};
-	uint32_t height{};
-
-	Point() = default;
-
-	Point(uint32_t width, uint32_t height)
-		: width(width)
-		, height(height)
-	{
-	}
-
-	inline bool operator==(const Point &other) const
-	{
-		return width == other.width && height == other.height;
-	}
-};
-
-template <>
-struct Pack::TypeInfo<Point> : public Pack::Serializable
-{
-	static void serialize(PackWriter &writer, const Point &point)
-	{
-		writer << point.width << point.height;
-	}
-
-	static void unserialize(PackReader &reader, Point &point)
-	{
-		reader >> point.width >> point.height;
-	}
-};
-
-TEST(File, simpleLittleEndian)
-{
-	uint8_t u8(1), r8;
-	uint16_t u16(2), r16;
-	uint32_t u32(3), r32;
-	uint64_t u64(4), r64;
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Little};
-			writer << u8 << u16 << u32 << u64;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Little};
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(File, simpleBigEndian)
-{
-	uint8_t u8(1), r8;
-	uint16_t u16(2), r16;
-	uint32_t u32(3), r32;
-	uint64_t u64(4), r64;
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Big};
-			writer << u8 << u16 << u32 << u64;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Big};
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(File, arrayLittleEndian)
-{
-	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
-	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
-	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
-	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
-
-	std::vector<uint8_t> r8(8);
-	std::vector<uint16_t> r16(8);
-	std::vector<uint32_t> r32(8);
-	std::vector<uint64_t> r64(8);
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Little};
-
-			writer << u8 << u16 << u32 << u64;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Little};
-
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(File, arrayBigEndian)
-{
-	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
-	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
-	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
-	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
-
-	std::vector<uint8_t> r8(8);
-	std::vector<uint16_t> r16(8);
-	std::vector<uint32_t> r32(8);
-	std::vector<uint64_t> r64(8);
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Big};
-
-			writer << u8 << u16 << u32 << u64;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Big};
-
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(File, serializeSimpleLittleEndian)
-{
-	Point point{200, 400};
-	Point result;
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Little};
-
-			writer << point;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Little};
-
-		reader >> result;
-
-		ASSERT_EQ(point, result);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(File, serializeSimpleBigEndian)
-{
-	Point point{200, 400};
-	Point result;
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Big};
-
-			writer << point;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Big};
-
-		reader >> result;
-
-		ASSERT_EQ(point, result);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(File, serializeArrayLittleEndian)
-{
-	std::vector<Point> points{{10, 20}, {30, 40}};
-	std::vector<Point> rpoints(2);
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Little};
-
-			writer << points;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Little};
-
-		reader >> rpoints;
-
-		ASSERT_EQ(points, rpoints);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(File, serializeArrayBigEndian)
-{
-	std::vector<Point> points{{10, 20}, {30, 40}};
-	std::vector<Point> rpoints(2);
-
-	remove("output.bin");
-
-	try {
-		{
-			PackFileWriter writer{"output.bin", Pack::Big};
-
-			writer << points;
-		}
-
-		PackFileReader reader{"output.bin", Pack::Big};
-
-		reader >> rpoints;
-
-		ASSERT_EQ(points, rpoints);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(String, simpleLittleEndian)
-{
-	uint8_t u8(1), r8;
-	uint16_t u16(2), r16;
-	uint32_t u32(3), r32;
-	uint64_t u64(4), r64;
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Little};
-			writer << u8 << u16 << u32 << u64;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Little};
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(String, simpleBigEndian)
-{
-	uint8_t u8(1), r8;
-	uint16_t u16(2), r16;
-	uint32_t u32(3), r32;
-	uint64_t u64(4), r64;
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Big};
-			writer << u8 << u16 << u32 << u64;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Big};
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(String, arrayLittleEndian)
-{
-	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
-	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
-	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
-	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
-
-	std::vector<uint8_t> r8(8);
-	std::vector<uint16_t> r16(8);
-	std::vector<uint32_t> r32(8);
-	std::vector<uint64_t> r64(8);
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Little};
-
-			writer << u8 << u16 << u32 << u64;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Little};
-
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(String, arrayBigEndian)
-{
-	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
-	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
-	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
-	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
-
-	std::vector<uint8_t> r8(8);
-	std::vector<uint16_t> r16(8);
-	std::vector<uint32_t> r32(8);
-	std::vector<uint64_t> r64(8);
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Big};
-
-			writer << u8 << u16 << u32 << u64;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Big};
-
-		reader >> r8 >> r16 >> r32 >> r64;
-
-		ASSERT_EQ(u8, r8);
-		ASSERT_EQ(u16, r16);
-		ASSERT_EQ(u32, r32);
-		ASSERT_EQ(u64, r64);
-	} catch (const std::exception &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(String, serializeSimpleLittleEndian)
-{
-	Point point{200, 400};
-	Point result;
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Little};
-
-			writer << point;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Little};
-
-		reader >> result;
-
-		ASSERT_EQ(point, result);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(String, serializeSimpleBigEndian)
-{
-	Point point{200, 400};
-	Point result;
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Big};
-
-			writer << point;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Big};
-
-		reader >> result;
-
-		ASSERT_EQ(point, result);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(String, serializeArrayLittleEndian)
-{
-	std::vector<Point> points{{10, 20}, {30, 40}};
-	std::vector<Point> rpoints(2);
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Little};
-
-			writer << points;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Little};
-
-		reader >> rpoints;
-
-		ASSERT_EQ(points, rpoints);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST(String, serializeArrayBigEndian)
-{
-	std::vector<Point> points{{10, 20}, {30, 40}};
-	std::vector<Point> rpoints(2);
-
-	try {
-		std::string input;
-
-		{
-			PackStringWriter writer{Pack::Big};
-
-			writer << points;
-			input = writer.buffer();
-		}
-
-		PackStringReader reader{std::move(input), Pack::Big};
-
-		reader >> rpoints;
-
-		ASSERT_EQ(points, rpoints);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Parser/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-#
-# CMakeLists.txt -- tests for Parser
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Parser.cpp
-	${code_SOURCE_DIR}/C++/Parser.h
-	main.cpp
-	configs/simple.conf
-	configs/multi.conf
-)
-
-define_test(parser "${SOURCES}")
-
-add_custom_command(
-	TARGET parser
-	POST_BUILD
-	COMMENT "Copying examples files"
-	COMMAND
-		${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/configs $<TARGET_FILE_DIR:parser>
-)
--- a/C++/Tests/Parser/configs/multi.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-[entity]
-name	= "Player"
-version	= 1.0
-
-[entity]
-name	= "Subwinner"
-version	= 2.0
\ No newline at end of file
--- a/C++/Tests/Parser/configs/simple.conf	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-[general]
-option1=1
-option2 =2
-option3 = 3
--- a/C++/Tests/Parser/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * TestParser.cpp -- test the config file parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <Parser.h>
-
-TEST(Basic, simple)
-{
-	try {
-		Parser parser("simple.conf");
-
-		const auto &s = parser.getSection("general");
-		ASSERT_EQ("general", s.getName());
-
-		const auto &o1 = s.getOption<std::string>("option1");
-		ASSERT_EQ("1", o1);
-
-		const auto &o2 = s.getOption<std::string>("option2");
-		ASSERT_EQ("2", o2);
-
-		const auto &o3 = s.getOption<std::string>("option3");
-		ASSERT_EQ("3", o3);
-	} catch (const std::out_of_range &error) {
-		FAIL();
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(Basic, multi)
-{
-	try {
-		Parser parser("multi.conf");
-		int i(0);
-
-		parser.findSections("entity", [&] (const Section &s) {
-			if (i++ == 0) {
-				ASSERT_EQ("Player", s.getOption<std::string>("name"));
-				ASSERT_EQ("1.0", s.getOption<std::string>("version"));
-			} else {
-				ASSERT_EQ("Subwinner", s.getOption<std::string>("name"));
-				ASSERT_EQ("2.0", s.getOption<std::string>("version"));
-			}
-		});
-
-		ASSERT_EQ(2, i);
-	} catch (const std::out_of_range &error) {
-		FAIL();
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(Basic, multiNoredef)
-{
-	try {
-		Parser parser("multi.conf", Parser::DisableRedefinition);
-		int i(0);
-
-		parser.findSections("entity", [&] (const Section &s) {
-			if (i++ == 0) {
-				ASSERT_EQ("Player", s.getOption<std::string>("name"));
-				ASSERT_EQ("1.0", s.getOption<std::string>("version"));
-			}
-		});
-
-		ASSERT_EQ(1, i);
-	} catch (const std::out_of_range &error) {
-		FAIL();
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
\ No newline at end of file
--- a/C++/Tests/Sockets/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-#
-# CMakeLists.txt -- tests for sockets
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-find_package(OpenSSL REQUIRED)
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Socket.cpp
-	${code_SOURCE_DIR}/C++/Socket.h
-	${code_SOURCE_DIR}/C++/SocketTcp.cpp
-	${code_SOURCE_DIR}/C++/SocketTcp.h
-	${code_SOURCE_DIR}/C++/SocketUdp.cpp
-	${code_SOURCE_DIR}/C++/SocketUdp.h
-	${code_SOURCE_DIR}/C++/SocketAddress.cpp
-	${code_SOURCE_DIR}/C++/SocketAddress.h
-	${code_SOURCE_DIR}/C++/SocketListener.cpp
-	${code_SOURCE_DIR}/C++/SocketListener.h
-	${code_SOURCE_DIR}/C++/SocketSsl.cpp
-	${code_SOURCE_DIR}/C++/SocketSsl.h
-	main.cpp
-)
-
-define_test(socket "${SOURCES}")
-
-if (WIN32)
-	target_link_libraries(socket ws2_32)
-endif ()
-
-target_include_directories(socket PRIVATE ${OPENSSL_INCLUDE_DIR})
-target_link_libraries(socket ${OPENSSL_LIBRARIES})
--- a/C++/Tests/Sockets/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,709 +0,0 @@
-/*
- * main.cpp -- test sockets
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <chrono>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include "Socket.h"
-#include "SocketAddress.h"
-#include "SocketListener.h"
-#include "SocketSsl.h"
-#include "SocketTcp.h"
-#include "SocketUdp.h"
-
-using namespace address;
-using namespace std::literals::chrono_literals;
-
-/* --------------------------------------------------------
- * TCP tests
- * -------------------------------------------------------- */
-
-class TcpServerTest : public testing::Test {
-protected:
-	SocketTcp m_server{AF_INET, 0};
-	SocketTcp m_client{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TcpServerTest()
-	{
-		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-	}
-
-	~TcpServerTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(TcpServerTest, connect)
-{
-	m_tserver = std::thread([this] () {
-		m_server.bind(Internet("*", 16000, AF_INET));
-
-		ASSERT_EQ(SocketState::Bound, m_server.state());
-
-		m_server.listen();
-		m_server.accept();
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-
-		ASSERT_EQ(SocketState::Connected, m_client.state());
-
-		m_client.close();
-	});
-}
-
-TEST_F(TcpServerTest, io)
-{
-	m_tserver = std::thread([this] () {
-		m_server.bind(Internet("*", 16000, AF_INET));
-		m_server.listen();
-
-		auto client = m_server.accept();
-		auto msg = client.recv(512);
-
-		ASSERT_EQ("hello world", msg);
-
-		client.send(msg);
-		client.close();
-
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_client.send("hello world");
-
-		ASSERT_EQ("hello world", m_client.recv(512));
-
-		m_client.close();
-	});
-}
-
-/* --------------------------------------------------------
- * UDP tests
- * -------------------------------------------------------- */
-
-class UdpServerTest : public testing::Test {
-protected:
-	SocketUdp m_server{AF_INET, 0};
-	SocketUdp m_client{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	UdpServerTest()
-	{
-		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-	}
-
-	~UdpServerTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(UdpServerTest, io)
-{
-	m_tserver = std::thread([this] () {
-		SocketAddress info;
-
-		m_server.bind(Internet("*", 16000, AF_INET));
-
-		auto msg = m_server.recvfrom(512, info);
-
-		ASSERT_EQ("hello world", msg);
-
-		m_server.sendto(msg, info);
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		Internet info("127.0.0.1", 16000, AF_INET);
-
-		m_client.sendto("hello world", info);
-
-		ASSERT_EQ("hello world", m_client.recvfrom(512, info));
-
-		m_client.close();
-	});
-}
-
-/* --------------------------------------------------------
- * Listener tests (standard)
- * -------------------------------------------------------- */
-
-class ListenerTest : public testing::Test {
-protected:
-	SocketListener m_listener;
-	SocketTcp socket1{AF_INET, 0};
-	SocketUdp socket2{AF_INET, 0};
-
-public:
-	~ListenerTest()
-	{
-		socket1.close();
-		socket2.close();
-	}
-};
-
-TEST_F(ListenerTest, set)
-{
-	m_listener.set(socket1, SocketListener::Read);
-
-	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
-	ASSERT_EQ(SocketListener::Read, m_listener.begin()->second);
-
-	m_listener.set(socket1, SocketListener::Write);
-
-	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
-	ASSERT_EQ(0x3, m_listener.begin()->second);
-
-	// Fake a re-insert of the same socket
-	m_listener.set(socket1, SocketListener::Write);
-
-	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
-	ASSERT_EQ(0x3, m_listener.begin()->second);
-
-	// Add an other socket now
-	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
-
-	ASSERT_EQ(2, static_cast<int>(m_listener.size()));
-
-	for (auto &pair : m_listener) {
-		ASSERT_EQ(0x3, pair.second);
-		ASSERT_TRUE(pair.first == socket1 || pair.first == socket2);
-	}
-}
-
-TEST_F(ListenerTest, unset)
-{
-	m_listener.set(socket1, SocketListener::Read | SocketListener::Write);
-	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
-
-	m_listener.unset(socket1, SocketListener::Read);
-
-	ASSERT_EQ(2, static_cast<int>(m_listener.size()));
-
-	// Use a for loop since it can be ordered differently
-	for (auto &pair : m_listener) {
-		if (pair.first == socket1) {
-			ASSERT_EQ(0x2, pair.second);
-		} else if (pair.first == socket2) {
-			ASSERT_EQ(0x3, pair.second);
-		}
-	}
-
-	m_listener.unset(socket1, SocketListener::Write);
-
-	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
-	ASSERT_EQ(0x3, m_listener.begin()->second);
-}
-
-TEST_F(ListenerTest, remove)
-{
-	m_listener.set(socket1, SocketListener::Read | SocketListener::Write);
-	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
-	m_listener.remove(socket1);
-
-	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
-	ASSERT_EQ(0x3, m_listener.begin()->second);
-}
-
-TEST_F(ListenerTest, clear)
-{
-	m_listener.set(socket1, SocketListener::Read | SocketListener::Write);
-	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
-	m_listener.clear();
-
-	ASSERT_EQ(0, static_cast<int>(m_listener.size()));
-}
-
-/* --------------------------------------------------------
- * Listener: poll
- * -------------------------------------------------------- */
-
-#if defined(SOCKET_HAVE_POLL)
-
-class ListenerPollTest : public testing::Test {
-protected:
-	SocketListener m_listener{SocketMethod::Poll};
-	SocketTcp m_masterTcp{AF_INET, 0};
-	SocketTcp m_clientTcp{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	ListenerPollTest()
-	{
-		m_masterTcp.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_masterTcp.bind(Internet("*", 16000, AF_INET));
-		m_masterTcp.listen();
-	}
-
-	~ListenerPollTest()
-	{
-		if (m_tserver.joinable()) {
-			m_tserver.join();
-		}
-		if (m_tclient.joinable()) {
-			m_tclient.join();
-		}
-	}
-};
-
-TEST_F(ListenerPollTest, accept)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_listener.set(m_masterTcp, SocketListener::Read);
-			m_listener.select();
-			m_masterTcp.accept();
-			m_masterTcp.close();
-		} catch (const std::exception &ex) {
-			FAIL() << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
-	});
-}
-
-TEST_F(ListenerPollTest, recv)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_listener.set(m_masterTcp, SocketListener::Read);
-			m_listener.select();
-
-			auto sc = m_masterTcp.accept();
-
-			ASSERT_EQ("hello", sc.recv(512));
-
-			m_masterTcp.close();
-		} catch (const std::exception &ex) {
-			FAIL() << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_clientTcp.send("hello");
-	});
-}
-
-#endif
-
-/* --------------------------------------------------------
- * Listener: select
- * -------------------------------------------------------- */
-
-class ListenerSelectTest : public testing::Test {
-protected:
-	SocketListener m_listener{SocketMethod::Select};
-	SocketTcp m_masterTcp{AF_INET, 0};
-	SocketTcp m_clientTcp{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	ListenerSelectTest()
-	{
-		m_masterTcp.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_masterTcp.bind(Internet("*", 16000, AF_INET));
-		m_masterTcp.listen();
-	}
-
-	~ListenerSelectTest()
-	{
-		if (m_tserver.joinable()) {
-			m_tserver.join();
-		}
-		if (m_tclient.joinable()) {
-			m_tclient.join();
-		}
-	}
-};
-
-TEST_F(ListenerSelectTest, accept)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_listener.set(m_masterTcp, SocketListener::Read);
-			m_listener.select();
-			m_masterTcp.accept();
-			m_masterTcp.close();
-		} catch (const std::exception &ex) {
-			FAIL() << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
-	});
-}
-
-TEST_F(ListenerSelectTest, recv)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_listener.set(m_masterTcp, SocketListener::Read);
-			m_listener.select();
-
-			auto sc = m_masterTcp.accept();
-
-			ASSERT_EQ("hello", sc.recv(512));
-
-			m_masterTcp.close();
-		} catch (const std::exception &ex) {
-			FAIL() << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_clientTcp.send("hello");
-	});
-}
-
-/* --------------------------------------------------------
- * Non-blocking connect
- * -------------------------------------------------------- */
-
-class NonBlockingConnectTest : public testing::Test {
-protected:
-	SocketTcp m_server{AF_INET, 0};
-	SocketTcp m_client{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	NonBlockingConnectTest()
-	{
-		m_client.setBlockMode(false);
-	}
-
-	~NonBlockingConnectTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(NonBlockingConnectTest, success)
-{
-	m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-	m_server.bind(Internet("*", 16000, AF_INET));
-	m_server.listen();
-
-	m_tserver = std::thread([this] () {
-		SocketTcp client = m_server.accept();
-
-		m_server.close();
-		client.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		try {
-			m_client.waitConnect(Internet("127.0.0.1", 16000, AF_INET), 3000);
-		} catch (const SocketError &error) {
-			FAIL() << error.what();
-		}
-
-		ASSERT_EQ(SocketState::Connected, m_client.state());
-
-		m_client.close();
-	});
-}
-
-TEST_F(NonBlockingConnectTest, fail)
-{
-	/*
-	 * /!\ If you find a way to test this locally please tell me /!\
-	 */
-	m_tclient = std::thread([this] () {
-		try {
-			m_client.waitConnect(Internet("google.fr", 9000, AF_INET), 100);
-
-			FAIL() << "Expected exception, got success";
-		} catch (const SocketError &error) {
-			ASSERT_EQ(SocketError::Timeout, error.code());
-		}
-
-		m_client.close();
-	});
-}
-
-/* --------------------------------------------------------
- * TCP accept
- * -------------------------------------------------------- */
-
-class TcpAcceptTest : public testing::Test {
-protected:
-	SocketTcp m_server{AF_INET, 0};
-	SocketTcp m_client{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TcpAcceptTest()
-	{
-		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_server.bind(Internet("*", 16000, AF_INET));
-		m_server.listen();
-	}
-
-	~TcpAcceptTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(TcpAcceptTest, blockingWaitSuccess)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_server.waitAccept(3000).close();
-		} catch (const SocketError &error) {
-			FAIL() << error.what();
-		}
-
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_client.close();
-	});
-}
-
-TEST_F(TcpAcceptTest, nonBlockingWaitSuccess)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_server.setBlockMode(false);
-			m_server.waitAccept(3000).close();
-		} catch (const SocketError &error) {
-			FAIL() << error.what();
-		}
-
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_client.close();
-	});
-}
-
-TEST_F(TcpAcceptTest, nonBlockingWaitFail)
-{
-	// No client, no accept
-	try {
-		m_server.setBlockMode(false);
-		m_server.waitAccept(100).close();
-
-		FAIL() << "Expected exception, got success";
-	} catch (const SocketError &error) {
-		ASSERT_EQ(SocketError::Timeout, error.code());
-	}
-
-	m_server.close();
-}
-
-/* --------------------------------------------------------
- * TCP recv
- * -------------------------------------------------------- */
-
-class TcpRecvTest : public testing::Test {
-protected:
-	SocketTcp m_server{AF_INET, 0};
-	SocketTcp m_client{AF_INET, 0};
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TcpRecvTest()
-	{
-		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_server.bind(Internet("*", 16000, AF_INET));
-		m_server.listen();
-	}
-
-	~TcpRecvTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(TcpRecvTest, blockingSuccess)
-{
-	m_tserver = std::thread([this] () {
-		SocketTcp client = m_server.accept();
-
-		ASSERT_EQ("hello", client.recv(32));
-
-		client.close();
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_client.send("hello");
-		m_client.close();
-	});
-}
-
-TEST_F(TcpRecvTest, blockingWaitSuccess)
-{
-	m_tserver = std::thread([this] () {
-		SocketTcp client = m_server.accept();
-
-		ASSERT_EQ("hello", client.waitRecv(32, 3000));
-
-		client.close();
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_client.send("hello");
-		m_client.close();
-	});
-}
-
-TEST_F(TcpRecvTest, nonBlockingWaitSuccess)
-{
-	m_tserver = std::thread([this] () {
-		SocketTcp client = m_server.accept();
-
-		client.setBlockMode(false);
-
-		ASSERT_EQ("hello", client.waitRecv(32, 3000));
-
-		client.close();
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
-		m_client.send("hello");
-		m_client.close();
-	});
-}
-
-/* --------------------------------------------------------
- * Socket SSL
- * -------------------------------------------------------- */
-
-class SslTest : public testing::Test {
-protected:
-	SocketSsl client{AF_INET, 0};
-};
-
-TEST_F(SslTest, connect)
-{
-	try {
-		client.connect(Internet("google.fr", 443, AF_INET));
-		client.close();
-	} catch (const SocketError &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST_F(SslTest, recv)
-{
-	try {
-		client.connect(Internet("google.fr", 443, AF_INET));
-		client.send("GET / HTTP/1.0\r\n\r\n");
-
-		std::string msg = client.recv(512);
-		std::string content = msg.substr(0, 18);
-
-		ASSERT_EQ("HTTP/1.0 302 Found", content);
-
-		client.close();
-	} catch (const SocketError &error) {
-		FAIL() << error.what();
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/TreeNode/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- tests for TreeNode
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/TreeNode.h
-	main.cpp
-)
-
-define_test(treenode "${SOURCES}")
--- a/C++/Tests/TreeNode/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1561 +0,0 @@
-/*
- * main.cpp -- main test file for TreeNode
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <chrono>
-#include <iostream>
-#include <iterator>
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <TreeNode.h>
-
-class Object final : public TreeNode<Object> {
-private:
-	std::string	m_name;
-
-public:
-	Object(std::string name)
-		: TreeNode()
-	{
-		m_name = std::move(name);
-	}
-
-	const std::string &name() const
-	{
-		return m_name;
-	}
-
-	friend bool operator==(const Object &o1, const Object &o2);
-};
-
-bool operator==(const Object &o1, const Object &o2)
-{
-	return o1.name() == o2.name();
-}
-
-/*
- * Random trees are created and then we test each node with the following preferred order:
- *
- * ASSERT_(TRUE|FALSE) isRoot()
- * ASSERT_(TRUE|FALSE) isLeaf()
- * ASSERT_EQ countChildren()
- * ASSERT_EQ() name()
- * ASSERT_TRUE & addresses
- */
-
-/* --------------------------------------------------------
- * Basic construction and insertion
- * -------------------------------------------------------- */
-
-/*
- * @root
- */
-TEST(Basic, construct)
-{
-	Object object("root");
-
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_TRUE(object.isLeaf());
-	ASSERT_EQ(0, object.countChildren());
-	ASSERT_EQ("root", object.name());
-}
-
-/*
- * @root -> append move -> @root
- *                         |
- *                         @a
- */
-TEST(Insertion, simpleAppendMove)
-{
-	Object object("root");
-	Object a("a");
-
-	object.append(std::move(a));
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(1, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test moved a
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ("a", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test original a
-	ASSERT_TRUE(a.isRoot());
-	ASSERT_TRUE(a.isLeaf());
-	ASSERT_EQ(0, a.countChildren());
-}
-
-/*
- * @root -> append copy -> @root
- *                         |
- *                         @a
- */
-TEST(Insertion, simpleAppendCopy)
-{
-	Object object("root");
-	Object copy("b");
-
-	object.append(copy);
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(1, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test copied b
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ("b", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test original b
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_TRUE(copy.isLeaf());
-	ASSERT_EQ(0, copy.countChildren());
-	ASSERT_EQ("b", copy.name());
-}
-
-/*
- * @root -> append move -> @root
- *                        / \
- *                      1@   @2
- */
-TEST(Insertion, doubleAppendMove)
-{
-	Object object("root");
-	Object o1("1");
-	Object o2("2");
-
-	object.append(std::move(o1));
-	object.append(std::move(o2));
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(2, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test moved 1
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ(0, object[0].countChildren());
-	ASSERT_EQ("1", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test moved 2
-	ASSERT_FALSE(object[1].isRoot());
-	ASSERT_TRUE(object[1].isLeaf());
-	ASSERT_EQ("2", object[1].name());
-	ASSERT_EQ(0, object[1].countChildren());
-	ASSERT_TRUE(&object == &object[1].parent());
-
-	// test original 1
-	ASSERT_TRUE(o1.isRoot());
-	ASSERT_TRUE(o1.isLeaf());
-	ASSERT_EQ(0, o1.countChildren());
-
-	// test original 2
-	ASSERT_TRUE(o2.isRoot());
-	ASSERT_TRUE(o2.isLeaf());
-	ASSERT_EQ(0, o2.countChildren());
-}
-
-/*
- * @root -> append copy -> @root
- *                        / \
- *                      1@   @2
- */
-TEST(Insertion, doubleAppendCopy)
-{
-	Object object("root");
-	Object o1("1");
-	Object o2("2");
-
-	object.append(o1);
-	object.append(o2);
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(2, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test copied 1
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ(0, object[0].countChildren());
-	ASSERT_EQ("1", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test copied 2
-	ASSERT_FALSE(object[1].isRoot());
-	ASSERT_TRUE(object[1].isLeaf());
-	ASSERT_EQ(0, object[1].countChildren());
-	ASSERT_EQ("2", object[1].name());
-	ASSERT_TRUE(&object == &object[1].parent());
-
-	// test original 1
-	ASSERT_TRUE(o1.isRoot());
-	ASSERT_TRUE(o1.isLeaf());
-	ASSERT_EQ(0, o1.countChildren());
-	ASSERT_EQ("1", o1.name());
-
-	// test original 2
-	ASSERT_TRUE(o2.isRoot());
-	ASSERT_TRUE(o2.isLeaf());
-	ASSERT_EQ(0, o2.countChildren());
-	ASSERT_EQ("2", o2.name());
-}
-
-/*
- * @root -> push move -> @root
- *                       |
- *                       @a
- */
-TEST(Insertion, simplePushMove)
-{
-	Object object("root");
-	Object a("a");
-
-	object.push(std::move(a));
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(1, object.countChildren());
-	ASSERT_EQ("a", object[0].name());
-
-	// test moved a
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ(0, object[0].countChildren());
-	ASSERT_EQ("a", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test original a
-	ASSERT_TRUE(a.isRoot());
-	ASSERT_TRUE(a.isLeaf());
-	ASSERT_EQ(0, a.countChildren());
-}
-
-/*
- * @root -> push copy -> @root
- *                       |
- *                       @a
- */
-TEST(Insertion, simplePushCopy)
-{
-	Object object("root");
-	Object copy("a");
-
-	object.push(copy);
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(1, object.countChildren());
-	ASSERT_EQ("a", object[0].name());
-
-	// test copied a
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ(0, object[0].countChildren());
-	ASSERT_EQ("a", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test original b
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_TRUE(copy.isLeaf());
-	ASSERT_EQ(0, copy.countChildren());
-	ASSERT_EQ("a", copy.name());
-}
-
-/*
- * @root -> push move -> @root
- *                      / \
- *                    2@   @1
- */
-TEST(Insertion, doublePushMove)
-{
-	Object object("root");
-	Object o1("1");
-	Object o2("2");
-
-	object.push(std::move(o1));
-	object.push(std::move(o2));
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(2, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test moved 2
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ(0, object[0].countChildren());
-	ASSERT_EQ("2", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test moved 1
-	ASSERT_FALSE(object[1].isRoot());
-	ASSERT_TRUE(object[1].isLeaf());
-	ASSERT_EQ("1", object[1].name());
-	ASSERT_EQ(0, object[1].countChildren());
-	ASSERT_TRUE(&object == &object[1].parent());
-
-	// test original 1
-	ASSERT_TRUE(o1.isRoot());
-	ASSERT_TRUE(o1.isLeaf());
-	ASSERT_EQ(0, o1.countChildren());
-
-	// test original 2
-	ASSERT_TRUE(o2.isRoot());
-	ASSERT_TRUE(o2.isLeaf());
-	ASSERT_EQ(0, o2.countChildren());
-}
-
-/*
- * @root -> push copy -> @root
- *                      / \
- *                    2@   @1
- */
-TEST(Insertion, doublePushCopy)
-{
-	Object object("root");
-	Object o1("1");
-	Object o2("2");
-
-	object.push(o1);
-	object.push(o2);
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(2, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test copied 2
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_TRUE(object[0].isLeaf());
-	ASSERT_EQ(0, object[0].countChildren());
-	ASSERT_EQ("2", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test copied 1
-	ASSERT_FALSE(object[1].isRoot());
-	ASSERT_TRUE(object[1].isLeaf());
-	ASSERT_EQ(0, object[1].countChildren());
-	ASSERT_EQ("1", object[1].name());
-	ASSERT_TRUE(&object == &object[1].parent());
-
-	// test original 1
-	ASSERT_TRUE(o1.isRoot());
-	ASSERT_TRUE(o1.isLeaf());
-	ASSERT_EQ(0, o1.countChildren());
-	ASSERT_EQ("1", o1.name());
-
-	// test original 2
-	ASSERT_TRUE(o2.isRoot());
-	ASSERT_TRUE(o2.isLeaf());
-	ASSERT_EQ(0, o2.countChildren());
-	ASSERT_EQ("2", o2.name());
-}
-
-/* --------------------------------------------------------
- * Sub insertion
- * -------------------------------------------------------- */
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b
- *        / \   / \
- *      c@  d@ @e  @f
- */
-TEST(SubInsert, append)
-{
-	Object object("root");
-
-	object.append(Object("a"));
-	object.append(Object("b"));
-
-	object[0].append(Object("c"));
-	object[0].append(Object("d"));
-	object[1].append(Object("e"));
-	object[1].append(Object("f"));
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(2, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test a
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_FALSE(object[0].isLeaf());
-	ASSERT_EQ(2, object[0].countChildren());
-	ASSERT_EQ("a", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test b
-	ASSERT_FALSE(object[1].isRoot());
-	ASSERT_FALSE(object[1].isLeaf());
-	ASSERT_EQ(2, object[1].countChildren());
-	ASSERT_EQ("b", object[1].name());
-	ASSERT_TRUE(&object == &object[1].parent());
-
-	// test c
-	ASSERT_FALSE(object[0][0].isRoot());
-	ASSERT_TRUE(object[0][0].isLeaf());
-	ASSERT_EQ(0, object[0][0].countChildren());
-	ASSERT_EQ("c", object[0][0].name());
-	ASSERT_TRUE(&object[0] == &object[0][0].parent());
-
-	// test d
-	ASSERT_FALSE(object[0][1].isRoot());
-	ASSERT_TRUE(object[0][1].isLeaf());
-	ASSERT_EQ(0, object[0][1].countChildren());
-	ASSERT_EQ("d", object[0][1].name());
-	ASSERT_TRUE(&object[0] == &object[0][1].parent());
-
-	// test e
-	ASSERT_FALSE(object[1][0].isRoot());
-	ASSERT_TRUE(object[1][0].isLeaf());
-	ASSERT_EQ(0, object[1][0].countChildren());
-	ASSERT_EQ("e", object[1][0].name());
-	ASSERT_TRUE(&object[1] == &object[1][0].parent());
-
-	// test f
-	ASSERT_FALSE(object[1][1].isRoot());
-	ASSERT_TRUE(object[1][1].isLeaf());
-	ASSERT_EQ(0, object[1][1].countChildren());
-	ASSERT_EQ("f", object[1][1].name());
-	ASSERT_TRUE(&object[1] == &object[1][1].parent());
-}
-
-/*
- *            @root
- *           / \
- *          /   \
- *        b@     @a
- *        / \   / \
- *      d@  c@ @f  @e
- */
-TEST(SubInsert, push)
-{
-	Object object("root");
-
-	object.push(Object("a"));
-	object.push(Object("b"));
-
-	object[0].push(Object("c"));
-	object[0].push(Object("d"));
-	object[1].push(Object("e"));
-	object[1].push(Object("f"));
-
-	// test root
-	ASSERT_TRUE(object.isRoot());
-	ASSERT_FALSE(object.isLeaf());
-	ASSERT_EQ(2, object.countChildren());
-	ASSERT_EQ("root", object.name());
-
-	// test b
-	ASSERT_FALSE(object[0].isRoot());
-	ASSERT_FALSE(object[0].isLeaf());
-	ASSERT_EQ(2, object[0].countChildren());
-	ASSERT_EQ("b", object[0].name());
-	ASSERT_TRUE(&object == &object[0].parent());
-
-	// test a
-	ASSERT_FALSE(object[1].isRoot());
-	ASSERT_FALSE(object[1].isLeaf());
-	ASSERT_EQ(2, object[1].countChildren());
-	ASSERT_EQ("a", object[1].name());
-	ASSERT_TRUE(&object == &object[1].parent());
-
-	// test d
-	ASSERT_FALSE(object[0][0].isRoot());
-	ASSERT_TRUE(object[0][0].isLeaf());
-	ASSERT_EQ(0, object[0][0].countChildren());
-	ASSERT_EQ("d", object[0][0].name());
-	ASSERT_TRUE(&object[0] == &object[0][0].parent());
-
-	// test c
-	ASSERT_FALSE(object[0][1].isRoot());
-	ASSERT_TRUE(object[0][1].isLeaf());
-	ASSERT_EQ(0, object[0][1].countChildren());
-	ASSERT_EQ("c", object[0][1].name());
-	ASSERT_TRUE(&object[0] == &object[0][1].parent());
-
-	// test f
-	ASSERT_FALSE(object[1][0].isRoot());
-	ASSERT_TRUE(object[1][0].isLeaf());
-	ASSERT_EQ(0, object[1][0].countChildren());
-	ASSERT_EQ("f", object[1][0].name());
-	ASSERT_TRUE(&object[1] == &object[1][0].parent());
-
-	// test e
-	ASSERT_FALSE(object[1][1].isRoot());
-	ASSERT_TRUE(object[1][1].isLeaf());
-	ASSERT_EQ(0, object[1][1].countChildren());
-	ASSERT_EQ("e", object[1][1].name());
-	ASSERT_TRUE(&object[1] == &object[1][1].parent());
-}
-
-/* --------------------------------------------------------
- * Move constructor
- * -------------------------------------------------------- */
-
-TEST(MoveConstructor, simple)
-{
-	Object root("root");
-	Object moved(std::move(root));
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_TRUE(root.isLeaf());
-	ASSERT_EQ(0, root.countChildren());
-
-	// test moved
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_TRUE(moved.isLeaf());
-	ASSERT_EQ(0, moved.countChildren());
-	ASSERT_EQ("root", moved.name());
-}
-
-/*
- *            @root -> copy
- *           / \
- *          /   \
- *        a@     @b 
- */
-TEST(MoveConstructor, oneLevel)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	Object moved(std::move(root));
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_EQ(2, moved.countChildren());
-	ASSERT_EQ("a", moved[0].name());
-	ASSERT_EQ("b", moved[1].name());
-	ASSERT_EQ("root", moved[0].parent().name());
-	ASSERT_EQ("root", moved[1].parent().name());
-	ASSERT_TRUE(&moved == &moved[0].parent());
-	ASSERT_TRUE(&moved == &moved[1].parent());
-}
-
-/*
- *            @root -> copy
- *           / \
- *          /   \
- *        a@     @b 
- *        / \   / \
- *      c@  d@ @e  @f
- *
- */
-TEST(MoveConstructor, twoLevels)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	root[0].append(Object("c"));
-	root[0].append(Object("d"));
-	root[1].append(Object("e"));
-	root[1].append(Object("f"));
-
-	Object moved(std::move(root));
-
-	// test root
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_EQ(2, moved.countChildren());
-
-	// test a, b
-	ASSERT_EQ("a", moved[0].name());
-	ASSERT_EQ("b", moved[1].name());
-	ASSERT_EQ(2, moved[0].countChildren());
-	ASSERT_EQ(2, moved[1].countChildren());
-	ASSERT_EQ("root", moved[0].parent().name());
-	ASSERT_EQ("root", moved[1].parent().name());
-	ASSERT_TRUE(&moved == &moved[0].parent());
-	ASSERT_TRUE(&moved == &moved[1].parent());
-
-	// test c, d
-	ASSERT_EQ("c", moved[0][0].name());
-	ASSERT_EQ("d", moved[0][1].name());
-	ASSERT_EQ("a", moved[0][0].parent().name());
-	ASSERT_EQ("a", moved[0][1].parent().name());
-	ASSERT_TRUE(&moved[0] == &moved[0][0].parent());
-	ASSERT_TRUE(&moved[0] == &moved[0][1].parent());
-	ASSERT_TRUE(moved[0][0].isLeaf());
-	ASSERT_TRUE(moved[0][1].isLeaf());
-	ASSERT_FALSE(moved[0][0].isRoot());
-	ASSERT_FALSE(moved[0][1].isRoot());
-
-	// test e, f
-	ASSERT_EQ("e", moved[1][0].name());
-	ASSERT_EQ("f", moved[1][1].name());
-	ASSERT_EQ("b", moved[1][0].parent().name());
-	ASSERT_EQ("b", moved[1][1].parent().name());
-	ASSERT_TRUE(&moved[1] == &moved[1][0].parent());
-	ASSERT_TRUE(&moved[1] == &moved[1][1].parent());
-	ASSERT_TRUE(moved[1][0].isLeaf());
-	ASSERT_TRUE(moved[1][1].isLeaf());
-	ASSERT_FALSE(moved[1][0].isRoot());
-	ASSERT_FALSE(moved[1][1].isRoot());
-}
-
-/* --------------------------------------------------------
- * Copy constructor
- * -------------------------------------------------------- */
-
-TEST(CopyConstructor, simple)
-{
-	Object root("root");
-	Object moved(root);
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_TRUE(root.isLeaf());
-	ASSERT_EQ(0, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test copy
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_TRUE(moved.isLeaf());
-	ASSERT_EQ(0, moved.countChildren());
-	ASSERT_EQ("root", moved.name());
-}
-
-/*
- *            @root -> copy
- *           / \
- *          /   \
- *        a@     @b 
- */
-TEST(CopyConstructor, oneLevel)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	Object copy(root);
-
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_FALSE(copy.isLeaf());
-	ASSERT_EQ("root", root.name());
-	ASSERT_EQ("root", copy.name());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ("b", root[1].name());
-	ASSERT_EQ("a", copy[0].name());
-	ASSERT_EQ("b", copy[1].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-	ASSERT_TRUE(&root == &root[1].parent());
-	ASSERT_TRUE(&copy == &copy[0].parent());
-	ASSERT_TRUE(&copy == &copy[1].parent());
-}
-
-/*
- *            @root -> copy
- *           / \
- *          /   \
- *        a@     @b 
- *        / \   / \
- *      c@  d@ @e  @f
- *
- */
-TEST(CopyConstructor, twoLevels)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	root[0].append(Object("c"));
-	root[0].append(Object("d"));
-	root[1].append(Object("e"));
-	root[1].append(Object("f"));
-
-	Object copy(root);
-
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_FALSE(copy.isLeaf());
-	ASSERT_EQ("root", root.name());
-	ASSERT_EQ("root", copy.name());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ("a", copy[0].name());
-	ASSERT_EQ("c", root[0][0].name());
-	ASSERT_EQ("c", copy[0][0].name());
-	ASSERT_EQ("d", root[0][1].name());
-	ASSERT_EQ("d", copy[0][1].name());
-	ASSERT_EQ("b", root[1].name());
-	ASSERT_EQ("b", copy[1].name());
-	ASSERT_EQ("e", root[1][0].name());
-	ASSERT_EQ("e", copy[1][0].name());
-	ASSERT_EQ("f", root[1][1].name());
-	ASSERT_EQ("f", copy[1][1].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-	ASSERT_TRUE(&root == &root[1].parent());
-	ASSERT_TRUE(&copy == &copy[0].parent());
-	ASSERT_TRUE(&copy == &copy[1].parent());
-	ASSERT_TRUE(&root[0] == &root[0][0].parent());
-	ASSERT_TRUE(&root[0] == &root[0][1].parent());
-	ASSERT_TRUE(&copy[0] == &copy[0][0].parent());
-	ASSERT_TRUE(&copy[0] == &copy[0][1].parent());
-	ASSERT_TRUE(&root[1] == &root[1][0].parent());
-	ASSERT_TRUE(&root[1] == &root[1][1].parent());
-	ASSERT_TRUE(&copy[1] == &copy[1][0].parent());
-	ASSERT_TRUE(&copy[1] == &copy[1][1].parent());
-}
-
-/* --------------------------------------------------------
- * Move extraction
- * -------------------------------------------------------- */
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b -> move -> @b
- */
-TEST(MoveExtraction, simple)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	Object moved(std::move(root[1]));
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test a
-	ASSERT_TRUE(root[0].isLeaf());
-	ASSERT_FALSE(root[0].isRoot());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ(0, root[0].countChildren());
-	ASSERT_TRUE(&root == &root[0].parent());
-
-	// test b
-	ASSERT_TRUE(root[1].isLeaf());
-	ASSERT_FALSE(root[1].isRoot());
-	ASSERT_EQ(0, root[1].countChildren());
-	ASSERT_TRUE(&root == &root[1].parent());
-
-	// test moved b
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_TRUE(moved.isLeaf());
-	ASSERT_EQ(0, moved.countChildren());
-	ASSERT_EQ("b", moved.name());
-}
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b -> move
- *        / \   / \
- *      c@  d@ @e  @f
- *                  \
- *                   @g
- */
-TEST(MoveExtraction, bigger)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	root[0].append(Object("c"));
-	root[0].append(Object("d"));
-	root[1].append(Object("e"));
-	root[1].append(Object("f"));
-	root[1][1].append(Object("g"));
-
-	Object moved(std::move(root[1]));
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test a
-	ASSERT_FALSE(root[0].isRoot());
-	ASSERT_FALSE(root[0].isLeaf());
-	ASSERT_EQ(2, root[0].countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-
-	// test c
-	ASSERT_FALSE(root[0][0].isRoot());
-	ASSERT_TRUE(root[0][0].isLeaf());
-	ASSERT_EQ(0, root[0][0].countChildren());
-	ASSERT_EQ("c", root[0][0].name());
-	ASSERT_TRUE(&root[0] == &root[0][0].parent());
-
-	// test d
-	ASSERT_FALSE(root[0][1].isRoot());
-	ASSERT_TRUE(root[0][1].isLeaf());
-	ASSERT_EQ(0, root[0][1].countChildren());
-	ASSERT_EQ("d", root[0][1].name());
-	ASSERT_TRUE(&root[0] == &root[0][1].parent());
-
-	// test b
-	ASSERT_FALSE(root[1].isRoot());
-	ASSERT_TRUE(root[1].isLeaf());
-	ASSERT_EQ(0, root[1].countChildren());
-	ASSERT_TRUE(&root == &root[1].parent());
-
-	// test moved b
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_FALSE(moved.isLeaf());
-	ASSERT_EQ(2, moved.countChildren());
-	ASSERT_EQ("b", moved.name());
-
-	// test moved b-e
-	ASSERT_FALSE(moved[0].isRoot());
-	ASSERT_TRUE(moved[0].isLeaf());
-	ASSERT_EQ(0, moved[0].countChildren());
-	ASSERT_EQ("e", moved[0].name());
-	ASSERT_TRUE(&moved == &moved[0].parent());
-
-	// test moved b-f
-	ASSERT_FALSE(moved[1].isRoot());
-	ASSERT_FALSE(moved[1].isLeaf());
-	ASSERT_EQ(1, moved[1].countChildren());
-	ASSERT_EQ("f", moved[1].name());
-	ASSERT_TRUE(&moved == &moved[1].parent());
-
-	// test moved b-g
-	ASSERT_FALSE(moved[1][0].isRoot());
-	ASSERT_TRUE(moved[1][0].isLeaf());
-	ASSERT_EQ(0, moved[1][0].countChildren());
-	ASSERT_EQ("g", moved[1][0].name());
-	ASSERT_TRUE(&moved[1] == &moved[1][0].parent());
-}
-
-/* --------------------------------------------------------
- * Copy extraction
- * -------------------------------------------------------- */
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b -> copy -> @b
- */
-TEST(CopyExtraction, simple)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	Object copy(root[1]);
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test a
-	ASSERT_TRUE(root[0].isLeaf());
-	ASSERT_FALSE(root[0].isRoot());
-	ASSERT_EQ(0, root[0].countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-
-	// test b
-	ASSERT_TRUE(root[1].isLeaf());
-	ASSERT_FALSE(root[1].isRoot());
-	ASSERT_EQ(0, root[1].countChildren());
-	ASSERT_EQ("b", root[1].name());
-	ASSERT_TRUE(&root == &root[1].parent());
-
-	// test copied b
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_TRUE(copy.isLeaf());
-	ASSERT_EQ(0, copy.countChildren());
-	ASSERT_EQ("b", copy.name());
-}
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b -> copy
- *        / \   / \
- *      c@  d@ @e  @f
- *                  \
- *                   @g
- */
-TEST(CopyExtraction, bigger)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	root[0].append(Object("c"));
-	root[0].append(Object("d"));
-	root[1].append(Object("e"));
-	root[1].append(Object("f"));
-	root[1][1].append(Object("g"));
-
-	Object copy(root[1]);
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test a
-	ASSERT_FALSE(root[0].isRoot());
-	ASSERT_FALSE(root[0].isLeaf());
-	ASSERT_EQ(2, root[0].countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-
-	// test c
-	ASSERT_FALSE(root[0][0].isRoot());
-	ASSERT_TRUE(root[0][0].isLeaf());
-	ASSERT_EQ(0, root[0][0].countChildren());
-	ASSERT_EQ("c", root[0][0].name());
-	ASSERT_TRUE(&root[0] == &root[0][0].parent());
-
-	// test d
-	ASSERT_FALSE(root[0][1].isRoot());
-	ASSERT_TRUE(root[0][1].isLeaf());
-	ASSERT_EQ(0, root[0][1].countChildren());
-	ASSERT_EQ("d", root[0][1].name());
-	ASSERT_TRUE(&root[0] == &root[0][1].parent());
-
-	// test b
-	ASSERT_FALSE(root[1].isRoot());
-	ASSERT_FALSE(root[1].isLeaf());
-	ASSERT_EQ(2, root[1].countChildren());
-	ASSERT_TRUE(&root == &root[1].parent());
-
-	// test e
-	ASSERT_FALSE(root[1][0].isRoot());
-	ASSERT_TRUE(root[1][0].isLeaf());
-	ASSERT_EQ(0, root[1][0].countChildren());
-	ASSERT_EQ("e", root[1][0].name());
-	ASSERT_TRUE(&root[1] == &root[1][0].parent());
-
-	// test f
-	ASSERT_FALSE(root[1][1].isRoot());
-	ASSERT_FALSE(root[1][1].isLeaf());
-	ASSERT_EQ(1, root[1][1].countChildren());
-	ASSERT_EQ("f", root[1][1].name());
-	ASSERT_TRUE(&root[1] == &root[1][1].parent());
-
-	// test g
-	ASSERT_FALSE(root[1][1][0].isRoot());
-	ASSERT_TRUE(root[1][1][0].isLeaf());
-	ASSERT_EQ(0, root[1][1][0].countChildren());
-	ASSERT_EQ("g", root[1][1][0].name());
-	ASSERT_TRUE(&root[1][1] == &root[1][1][0].parent());
-
-	// test copied b
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_FALSE(copy.isLeaf());
-	ASSERT_EQ(2, copy.countChildren());
-	ASSERT_EQ("b", copy.name());
-
-	// test copied b-e
-	ASSERT_FALSE(copy[0].isRoot());
-	ASSERT_TRUE(copy[0].isLeaf());
-	ASSERT_EQ(0, copy[0].countChildren());
-	ASSERT_EQ("e", copy[0].name());
-	ASSERT_TRUE(&copy == &copy[0].parent());
-
-	// test copied b-f
-	ASSERT_FALSE(copy[1].isRoot());
-	ASSERT_FALSE(copy[1].isLeaf());
-	ASSERT_EQ(1, copy[1].countChildren());
-	ASSERT_EQ("f", copy[1].name());
-	ASSERT_TRUE(&copy == &copy[1].parent());
-
-	// test copied b-g
-	ASSERT_FALSE(copy[1][0].isRoot());
-	ASSERT_TRUE(copy[1][0].isLeaf());
-	ASSERT_EQ(0, copy[1][0].countChildren());
-	ASSERT_EQ("g", copy[1][0].name());
-	ASSERT_TRUE(&copy[1] == &copy[1][0].parent());
-}
-
-/* --------------------------------------------------------
- * Move assignment
- * -------------------------------------------------------- */
-
-/*
- * @root -> @moved
- */
-TEST(MoveAssignment, simple)
-{
-	Object root("root");
-	Object moved("dummy");
-
-	moved = std::move(root);
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_TRUE(root.isLeaf());
-	ASSERT_EQ(0, root.countChildren());
-	
-	// test moved
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_TRUE(moved.isLeaf());
-	ASSERT_EQ(0, moved.countChildren());
-	ASSERT_EQ("root", moved.name());
-}
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b <- move <- @x
- *        / \   / \           / \
- *      c@  d@ @e  @f       y@   @z
- *                  \
- *                   @g
- */
-TEST(MoveAssignment, bigger)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	root[0].append(Object("c"));
-	root[0].append(Object("d"));
-	root[1].append(Object("e"));
-	root[1].append(Object("f"));
-	root[1][1].append(Object("g"));
-
-	Object moved("x");
-
-	moved.append(Object("y"));
-	moved.append(Object("z"));
-
-	root[1] = std::move(moved);
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test a
-	ASSERT_FALSE(root[0].isRoot());
-	ASSERT_FALSE(root[0].isLeaf());
-	ASSERT_EQ(2, root[0].countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-
-	// test c
-	ASSERT_FALSE(root[0][0].isRoot());
-	ASSERT_TRUE(root[0][0].isLeaf());
-	ASSERT_EQ(0, root[0][0].countChildren());
-	ASSERT_EQ("c", root[0][0].name());
-	ASSERT_TRUE(&root[0] == &root[0][0].parent());
-
-	// test copied x to b
-	ASSERT_FALSE(root[1].isRoot());
-	ASSERT_FALSE(root[1].isLeaf());
-	ASSERT_EQ(2, root[1].countChildren());
-	ASSERT_EQ("x", root[1].name());
-	ASSERT_TRUE(&root == &root[1].parent());
-
-	// test y
-	ASSERT_FALSE(root[1][0].isRoot());
-	ASSERT_TRUE(root[1][0].isLeaf());
-	ASSERT_EQ(0, root[1][0].countChildren());
-	ASSERT_EQ("y", root[1][0].name());
-	ASSERT_TRUE(&root[1] == &root[1][0].parent());
-
-	// test z
-	ASSERT_FALSE(root[1][1].isRoot());
-	ASSERT_TRUE(root[1][1].isLeaf());
-	ASSERT_EQ(0, root[1][1].countChildren());
-	ASSERT_EQ("z", root[1][1].name());
-	ASSERT_TRUE(&root[1] == &root[1][1].parent());
-
-	// test moved
-	ASSERT_TRUE(moved.isRoot());
-	ASSERT_TRUE(moved.isLeaf());
-	ASSERT_EQ(0, moved.countChildren());
-}
-
-/* --------------------------------------------------------
- * Copy assignment
- * -------------------------------------------------------- */
-
-/*
- * @root -> @copy
- */
-TEST(CopyAssignment, simple)
-{
-	Object root("root");
-	Object copy("copy");
-
-	copy = root;
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_TRUE(root.isLeaf());
-	ASSERT_EQ(0, root.countChildren());
-	ASSERT_EQ("root", root.name());
-	
-	// test copied
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_TRUE(copy.isLeaf());
-	ASSERT_EQ(0, copy.countChildren());
-	ASSERT_EQ("root", copy.name());
-}
-
-/*
- *            @root
- *           / \
- *          /   \
- *        a@     @b <- copy <- @x
- *        / \   / \           / \
- *      c@  d@ @e  @f       y@   @z
- *                  \
- *                   @g
- */
-TEST(CopyAssignment, bigger)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-
-	root[0].append(Object("c"));
-	root[0].append(Object("d"));
-	root[1].append(Object("e"));
-	root[1].append(Object("f"));
-	root[1][1].append(Object("g"));
-
-	Object copy("x");
-
-	copy.append(Object("y"));
-	copy.append(Object("z"));
-
-	root[1] = copy;
-
-	// test root
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("root", root.name());
-
-	// test a
-	ASSERT_FALSE(root[0].isRoot());
-	ASSERT_FALSE(root[0].isLeaf());
-	ASSERT_EQ(2, root[0].countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_TRUE(&root == &root[0].parent());
-
-	// test c
-	ASSERT_FALSE(root[0][0].isRoot());
-	ASSERT_TRUE(root[0][0].isLeaf());
-	ASSERT_EQ(0, root[0][0].countChildren());
-	ASSERT_EQ("c", root[0][0].name());
-	ASSERT_TRUE(&root[0] == &root[0][0].parent());
-
-	// test copied x to b
-	ASSERT_FALSE(root[1].isRoot());
-	ASSERT_FALSE(root[1].isLeaf());
-	ASSERT_EQ(2, root[1].countChildren());
-	ASSERT_EQ("x", root[1].name());
-	ASSERT_TRUE(&root == &root[1].parent());
-
-	// test y
-	ASSERT_FALSE(root[1][0].isRoot());
-	ASSERT_TRUE(root[1][0].isLeaf());
-	ASSERT_EQ(0, root[1][0].countChildren());
-	ASSERT_EQ("y", root[1][0].name());
-	ASSERT_TRUE(&root[1] == &root[1][0].parent());
-
-	// test z
-	ASSERT_FALSE(root[1][1].isRoot());
-	ASSERT_TRUE(root[1][1].isLeaf());
-	ASSERT_EQ(0, root[1][1].countChildren());
-	ASSERT_EQ("z", root[1][1].name());
-	ASSERT_TRUE(&root[1] == &root[1][1].parent());
-
-	// test original x
-	ASSERT_TRUE(copy.isRoot());
-	ASSERT_FALSE(copy.isLeaf());
-	ASSERT_EQ(2, copy.countChildren());
-	ASSERT_EQ("x", copy.name());
-
-	// test original y
-	ASSERT_FALSE(copy[0].isRoot());
-	ASSERT_TRUE(copy[0].isLeaf());
-	ASSERT_EQ(0, copy[0].countChildren());
-	ASSERT_EQ("y", copy[0].name());
-	ASSERT_TRUE(&copy == &copy[0].parent());
-
-	// test original z
-	ASSERT_FALSE(copy[1].isRoot());
-	ASSERT_TRUE(copy[1].isLeaf());
-	ASSERT_EQ(0, copy[1].countChildren());
-	ASSERT_EQ("z", copy[1].name());
-	ASSERT_TRUE(&copy == &copy[1].parent());
-}
-
-/* --------------------------------------------------------
- * Remove functions
- * -------------------------------------------------------- */
-
-TEST(Remove, clear)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-	root.clear();
-
-	ASSERT_EQ(0, root.countChildren());
-}
-
-TEST(Remove, index)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-	root.remove(2);
-
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ("b", root[1].name());
-}
-
-TEST(Remove, ref)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-	root.remove(root[2]);
-
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ("b", root[1].name());
-}
-
-TEST(Remove, same)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-	root.removeSame(Object("c"));
-
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ("b", root[1].name());
-}
-
-/* --------------------------------------------------------
- * Miscellaneous
- * -------------------------------------------------------- */
-
-TEST(Misc, indexOf)
-{
-	Object root("root");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-
-	ASSERT_EQ(1, root.indexOf(root[1]));
-}
-
-TEST(Misc, indexOfFail)
-{
-	Object root("root");
-	Object notin("c");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-
-	ASSERT_EQ(-1, root.indexOf(notin));
-}
-
-TEST(Misc, indexOfSame)
-{
-	Object root("root");
-	Object same("a");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-
-	ASSERT_EQ(0, root.indexOfSame(same));
-}
-
-TEST(Misc, indexOfSameFail)
-{
-	Object root("root");
-	Object same("xyz");
-
-	root.append(Object("a"));
-	root.append(Object("b"));
-	root.append(Object("c"));
-
-	ASSERT_EQ(-1, root.indexOfSame(same));
-}
-
-TEST(Misc, inplaceFront)
-{
-	Object root("root");
-
-	root.pushNew("a");
-	root.pushNew("b");
-
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("b", root[0].name());
-	ASSERT_EQ("a", root[1].name());
-}
-
-TEST(Misc, inplaceBack)
-{
-	Object root("root");
-
-	root.appendNew("a");
-	root.appendNew("b");
-
-	ASSERT_TRUE(root.isRoot());
-	ASSERT_FALSE(root.isLeaf());
-	ASSERT_EQ(2, root.countChildren());
-	ASSERT_EQ("a", root[0].name());
-	ASSERT_EQ("b", root[1].name());
-}
-
-TEST(Misc, map)
-{
-	Object root("root");
-	std::vector<Object> list;
-
-	root.appendNew("a");
-	root.appendNew("b");
-
-	root[0].appendNew("c");
-
-	root.map([&] (const auto &o) {
-		list.push_back(o);
-	});
-
-	ASSERT_EQ(4, list.size());
-	ASSERT_EQ("root", list[0].name());
-	ASSERT_EQ("a", list[1].name());
-	ASSERT_EQ("c", list[2].name());
-	ASSERT_EQ("b", list[3].name());
-}
-
-TEST(Misc, flat)
-{
-	Object root("root");
-	std::vector<Object> list;
-
-	root.appendNew("a");
-	root.appendNew("b");
-
-	root[0].appendNew("c");
-	root.flat(std::back_inserter(list));
-
-	ASSERT_EQ(4, list.size());
-	ASSERT_EQ("root", list[0].name());
-	ASSERT_EQ("a", list[1].name());
-	ASSERT_EQ("c", list[2].name());
-	ASSERT_EQ("b", list[3].name());
-}
-
-/* --------------------------------------------------------
- * Search
- * -------------------------------------------------------- */
-
-TEST(Search, returnsValue)
-{
-	Object root("root");
-
-	root.appendNew("a");
-	root.appendNew("b");
-
-	root[0].appendNew("c");
-
-	auto dummy = [] (Object &) {};
-
-	ASSERT_TRUE(root.search([] (const auto &v) { return v.name() == "a"; }, dummy));
-	ASSERT_TRUE(root.search([] (const auto &v) { return v.name() == "b"; }, dummy));
-	ASSERT_TRUE(root.search([] (const auto &v) { return v.name() == "c"; }, dummy));
-	ASSERT_FALSE(root.search([] (const auto &v) { return v.name() == "notavail"; }, dummy));
-}
-
-TEST(Search, returns)
-{
-	Object root("root");
-
-	root.appendNew("a");
-	root.appendNew("b");
-
-	root[0].appendNew("c");
-
-	try {
-		auto &a = root.search([] (const auto &o) {
-			return o.name() == "a";
-		});
-		auto &b = root.search([] (const auto &o) {
-			return o.name() == "b";
-		});
-		auto &c = root.search([] (const auto &o) {
-			return o.name() == "c";
-		});
-
-		ASSERT_EQ("a", a.name());
-		ASSERT_EQ("b", b.name());
-		ASSERT_EQ("c", c.name());
-
-		ASSERT_TRUE(&a == &root[0]);
-		ASSERT_TRUE(&b == &root[1]);
-		ASSERT_TRUE(&c == &root[0][0]);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Search, returnsFirst)
-{
-	Object root("root");
-
-	root.appendNew("a");
-	root.appendNew("a");
-	root.appendNew("a");
-
-	try {
-		auto &value = root.search([] (const auto &v) {
-			return v.name() == "a";
-		});
-
-		ASSERT_EQ("a", value.name());
-		ASSERT_TRUE(&value == &root[0]);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * Test inheritance
- * -------------------------------------------------------- */
-
-class Animal : public TreeNode<Animal> {
-public:
-	virtual ~Animal() = default;
-	virtual std::string noise() const
-	{
-		return "standard";
-	}
-};
-
-class Cat final : public Animal {
-public:
-	std::string noise() const override
-	{
-		return "miaou";
-	}
-};
-
-class Dog final : public Animal {
-public:
-	std::string noise() const override
-	{
-		return "waouf";
-	}
-};
-
-TEST(Inheritance, basic)
-{
-	Animal root;
-
-	root.append(Animal());
-	root.append(Cat());
-	root.append(Dog());
-
-	ASSERT_EQ("standard", root[0].noise());
-	ASSERT_EQ("miaou", root[1].noise());
-	ASSERT_EQ("waouf", root[2].noise());
-}
-
-TEST(Inheritance, copy)
-{
-	Animal root;
-
-	root.append(Animal());
-	root.append(Cat());
-	root.append(Dog());
-
-	ASSERT_EQ("standard", root[0].noise());
-	ASSERT_EQ("miaou", root[1].noise());
-	ASSERT_EQ("waouf", root[2].noise());
-
-	Animal copy(root);
-
-	ASSERT_EQ("standard", copy[0].noise());
-	ASSERT_EQ("miaou", copy[1].noise());
-	ASSERT_EQ("waouf", copy[2].noise());
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Utf8/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- tests for Utf8
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Utf8.cpp
-	${code_SOURCE_DIR}/C++/Utf8.h
-	main.cpp
-)
-
-define_test(utf8 "${SOURCES}")
--- a/C++/Tests/Utf8/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,327 +0,0 @@
-/*
- * main.cpp -- main test file for Utf8
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * /!\ Be sure to keep this file with UTF-8 encoding /!\
- */
-
-#include <gtest/gtest.h>
-
-#include <Utf8.h>
-
-using namespace testing;
-
-/* --------------------------------------------------------
- * Conversion UTF32 -> UTF8
- * -------------------------------------------------------- */
-
-TEST(Conversion32to8, ascii)
-{
-	try {
-		std::u32string u32{'a', 'b', 'c'};
-		std::string s = Utf8::toutf8(u32);
-
-		ASSERT_EQ("abc", s);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Conversion32to8, valid)
-{
-	try {
-		std::u32string u32{'a', /* é */ 233, 'c'};
-		std::string s = Utf8::toutf8(u32);
-
-		ASSERT_EQ("aéc", s);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Conversion32to8, invalid)
-{
-	try {
-		std::u32string u32{'a', 0xFFFFFFFF, 'c'};
-		std::string s = Utf8::toutf8(u32);
-
-		FAIL() << "expected a failure";
-	} catch (const std::exception &ex) {
-		SUCCEED();
-	}
-}
-
-/* --------------------------------------------------------
- * Conversion UTF8 -> UTF32
- * -------------------------------------------------------- */
-
-TEST(Conversion8to32, ascii)
-{
-	try {
-		std::string s{"abc"};
-		std::u32string expected{'a', 'b', 'c'};
-		std::u32string result = Utf8::toutf32(s);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Conversion8to32, valid)
-{
-	try {
-		std::string s{"aéc"};
-		std::u32string expected{'a', /* é */ 233, 'c'};
-		std::u32string result = Utf8::toutf32(s);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * UTF32 to upper
- * -------------------------------------------------------- */
-
-TEST(Toupper32, ascii)
-{
-	try {
-		std::u32string u32{'a', 'b', 'c'};
-		std::u32string expected{'A', 'B', 'C'};
-		std::u32string result = Utf8::toupper(u32);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Toupper32, valid)
-{
-	try {
-		std::u32string u32{/* ä */ 228, /* ç */ 231, /* ë */ 235};
-		std::u32string expected{/* Ä */ 196, /* Ç */ 199, /* Ë */ 203};
-		std::u32string result = Utf8::toupper(u32);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Toupper32, invalid)
-{
-	try {
-		std::u32string u32{'a', 0xFFFFFFFF, 'b'};
-		std::u32string expected{'A', 0xFFFFFFFF, 'B'};
-		std::u32string result = Utf8::toupper(u32);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * UTF32 to lower
- * -------------------------------------------------------- */
-
-TEST(Tolower32, ascii)
-{
-	try {
-		std::u32string u32{'A', 'B', 'C'};
-		std::u32string expected{'a', 'b', 'c'};
-		std::u32string result = Utf8::tolower(u32);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Tolower32, valid)
-{
-	try {
-		std::u32string u32{/* Ä */ 196, /* Ç */ 199, /* Ë */ 203};
-		std::u32string expected{/* ä */ 228, /* ç */ 231, /* ë */ 235};
-		std::u32string result = Utf8::tolower(u32);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Tolower32, invalid)
-{
-	try {
-		std::u32string u32{'A', 0xFFFFFFFF, 'B'};
-		std::u32string expected{'a', 0xFFFFFFFF, 'b'};
-		std::u32string result = Utf8::tolower(u32);
-
-		ASSERT_EQ(expected, result);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * UTF8 to upper
- * -------------------------------------------------------- */
-
-TEST(Toupper8, ascii)
-{
-	try {
-		std::string s{"abc"};
-		std::string r = Utf8::toupper(s);
-
-		ASSERT_EQ("ABC", r);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Toupper8, valid)
-{
-	try {
-		std::string s{"aéc"};
-		std::string r = Utf8::toupper(s);
-
-		ASSERT_EQ("AÉC", r);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Toupper8, invalid)
-{
-	try {
-		std::string s{"a" "\xFF""b"};
-		std::string r = Utf8::toupper(s);
-
-		FAIL() << "expected a failure";
-	} catch (const std::exception &ex) {
-		SUCCEED();
-	}
-}
-
-/* --------------------------------------------------------
- * UTF8 to lower
- * -------------------------------------------------------- */
-
-TEST(Tolower8, ascii)
-{
-	try {
-		std::string s{"ABC"};
-		std::string r = Utf8::tolower(s);
-
-		ASSERT_EQ("abc", r);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Tolower8, valid)
-{
-	try {
-		std::string s{"AÉC"};
-		std::string r = Utf8::tolower(s);
-
-		ASSERT_EQ("aéc", r);
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Tolower8, invalid)
-{
-	try {
-		std::string s{"A" "\xFF""B"};
-		std::string r = Utf8::tolower(s);
-
-		FAIL() << "expected a failure";
-	} catch (const std::exception &ex) {
-		SUCCEED();
-	}
-}
-
-/* --------------------------------------------------------
- * Check functions
- * -------------------------------------------------------- */
-
-TEST(Check, isspace)
-{
-	ASSERT_TRUE(Utf8::isspace(' '));
-	ASSERT_FALSE(Utf8::isspace(/* é */ 233));
-}
-
-TEST(Check, isletter)
-{
-	ASSERT_TRUE(Utf8::isletter(/* é */ 233));
-	ASSERT_FALSE(Utf8::isletter(/* € */ 8364));
-}
-
-TEST(Check, isupper)
-{
-	ASSERT_FALSE(Utf8::isupper('a'));
-	ASSERT_FALSE(Utf8::isupper(/* é */ 233));
-	ASSERT_TRUE(Utf8::isupper('A'));
-	ASSERT_TRUE(Utf8::isupper(/* É */ 201));
-}
-
-TEST(Check, islower)
-{
-	ASSERT_TRUE(Utf8::islower('a'));
-	ASSERT_TRUE(Utf8::islower(/* é */ 233));
-	ASSERT_FALSE(Utf8::islower('A'));
-	ASSERT_FALSE(Utf8::islower(/* É */ 201));
-}
-
-/* --------------------------------------------------------
- * Miscellaneous
- * -------------------------------------------------------- */
-
-TEST(Misc, nbytesPoint)
-{
-	ASSERT_EQ(1, Utf8::nbytesPoint('a'));
-	ASSERT_EQ(2, Utf8::nbytesPoint(/* é */ 233));
-	ASSERT_EQ(3, Utf8::nbytesPoint(/* € */ 8364));
-	ASSERT_EQ(4, Utf8::nbytesPoint(/* ð €€ */ 131072));
-}
-
-TEST(Misc, nbytesUtf8)
-{
-	std::string s1{"a"};
-	std::string s2{"é"};
-	std::string s3{"€"};
-	std::string s4{"ð €€"};
-
-	ASSERT_EQ(1, Utf8::nbytesUtf8(s1[0]));
-	ASSERT_EQ(2, Utf8::nbytesUtf8(s2[0]));
-	ASSERT_EQ(3, Utf8::nbytesUtf8(s3[0]));
-	ASSERT_EQ(4, Utf8::nbytesUtf8(s4[0]));	
-}
-
-int main(int argc, char **argv)
-{
-	InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Xdg/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- tests for XDG
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/Xdg.cpp
-	${code_SOURCE_DIR}/C++/Xdg.h
-	main.cpp
-)
-
-define_test(xdg "${SOURCES}")
--- a/C++/Tests/Xdg/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
-/*
- * main.cpp -- main test file for XDG
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <gtest/gtest.h>
-
-#include <Xdg.h>
-
-using namespace testing;
-
-namespace {
-
-std::string myhome;
-
-}
-
-TEST(HomeEmpty, config)
-{
-	ASSERT_TRUE(unsetenv("XDG_CONFIG_HOME") == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ(myhome + "/.config", xdg.configHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeEmpty, data)
-{
-	ASSERT_TRUE(unsetenv("XDG_DATA_HOME") == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ(myhome + "/.local/share", xdg.dataHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeEmpty, cache)
-{
-	ASSERT_TRUE(unsetenv("XDG_CACHE_HOME") == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ(myhome + "/.cache", xdg.cacheHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeEmpty, runtime)
-{
-	ASSERT_TRUE(unsetenv("XDG_RUNTIME_DIR") == 0);
-
-	try {
-		Xdg xdg;
-
-		try {
-			xdg.runtimeDir();
-
-			ASSERT_TRUE(false);
-		} catch (const std::exception &) { }
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeValid, config)
-{
-	ASSERT_TRUE(setenv("XDG_CONFIG_HOME", "/test/config", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ("/test/config", xdg.configHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeValid, data)
-{
-	ASSERT_TRUE(setenv("XDG_DATA_HOME", "/test/data", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ("/test/data", xdg.dataHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeValid, cache)
-{
-	ASSERT_TRUE(setenv("XDG_CACHE_HOME", "/test/cache", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ("/test/cache", xdg.cacheHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeValid, runtime)
-{
-	ASSERT_TRUE(setenv("XDG_RUNTIME_DIR", "/test/runtime", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ("/test/runtime", xdg.runtimeDir());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeInvalid, config)
-{
-	ASSERT_TRUE(setenv("XDG_CONFIG_HOME", "invalid", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ(myhome + "/.config", xdg.configHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeInvalid, data)
-{
-	ASSERT_TRUE(setenv("XDG_DATA_HOME", "invalid", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ(myhome + "/.local/share", xdg.dataHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeInvalid, cache)
-{
-	ASSERT_TRUE(setenv("XDG_CACHE_HOME", "invalid", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		ASSERT_EQ(myhome + "/.cache", xdg.cacheHome());
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(HomeInvalid, runtime)
-{
-	ASSERT_TRUE(setenv("XDG_RUNTIME_DIR", "invalid", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		try {
-			xdg.runtimeDir();
-
-			ASSERT_TRUE(false);
-		} catch (const std::exception &) { }
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesEmpty, config)
-{
-	ASSERT_TRUE(unsetenv("XDG_CONFIG_DIRS") == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.configDirs();
-
-		ASSERT_EQ((size_t)1, list.size());
-		ASSERT_EQ("/etc/xdg", list[0]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesEmpty, data)
-{
-	ASSERT_TRUE(unsetenv("XDG_DATA_DIRS") == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.dataDirs();
-
-		ASSERT_EQ((size_t)2, list.size());
-		ASSERT_EQ("/usr/local/share", list[0]);
-		ASSERT_EQ("/usr/share", list[1]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesValid, config)
-{
-	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "/config1:/config2", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.configDirs();
-
-		ASSERT_EQ((size_t)2, list.size());
-		ASSERT_EQ("/config1", list[0]);
-		ASSERT_EQ("/config2", list[1]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesValid, data)
-{
-	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "/data1:/data2", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.dataDirs();
-
-		ASSERT_EQ((size_t)2, list.size());
-		ASSERT_EQ("/data1", list[0]);
-		ASSERT_EQ("/data2", list[1]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesInvalid, config)
-{
-	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "bad1:bad2", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.configDirs();
-
-		ASSERT_EQ((size_t)1, list.size());
-		ASSERT_EQ("/etc/xdg", list[0]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesInvalid, data)
-{
-	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "bad1:bad2", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.dataDirs();
-
-		ASSERT_EQ((size_t)2, list.size());
-		ASSERT_EQ("/usr/local/share", list[0]);
-		ASSERT_EQ("/usr/share", list[1]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesMixed, config)
-{
-	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "/config1:bad:/config2", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.configDirs();
-
-		ASSERT_EQ((size_t)2, list.size());
-		ASSERT_EQ("/config1", list[0]);
-		ASSERT_EQ("/config2", list[1]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-TEST(DirectoriesMixed, data)
-{
-	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "/data1:bad:/data2", true) == 0);
-
-	try {
-		Xdg xdg;
-
-		const auto &list = xdg.dataDirs();
-
-		ASSERT_EQ((size_t)2, list.size());
-		ASSERT_EQ("/data1", list[0]);
-		ASSERT_EQ("/data2", list[1]);
-	} catch (const std::exception &) {
-		ASSERT_TRUE(false);
-	}
-}
-
-int main(int argc, char **argv)
-{
-	auto home = getenv("HOME");
-
-	if (home == nullptr)
-		return 0;
-
-	myhome = home;
-	InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/Tests/Zip/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#
-# CMakeLists.txt -- tests for Zip
-#
-# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(zip)
-
-find_package(ZIP REQUIRED)
-
-set(
-	SOURCES
-	${code_SOURCE_DIR}/C++/ZipArchive.cpp
-	${code_SOURCE_DIR}/C++/ZipArchive.h
-	${zip_SOURCE_DIR}/data/data.txt
-	main.cpp
-)
-
-define_test(zip "${SOURCES}")
-
-target_include_directories(zip PRIVATE ${ZIP_INCLUDE_DIRS})
-target_link_libraries(zip ${ZIP_LIBRARIES})
-target_compile_definitions(zip PRIVATE "SOURCE=\"${zip_SOURCE_DIR}\"" "BINARY=\"${zip_BINARY_DIR}\"")
--- a/C++/Tests/Zip/data/data.txt	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-abcdef
Binary file C++/Tests/Zip/data/stats.zip has changed
--- a/C++/Tests/Zip/main.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +0,0 @@
-/*
- * main.cpp -- test the zip wrapper functions
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <gtest/gtest.h>
-
-#include <ZipArchive.h>
-
-using namespace source;
-
-/* --------------------------------------------------------
- * Sources
- * -------------------------------------------------------- */
-
-TEST(Source, file)
-{
-	remove(BINARY "/output.zip");
-
-	try {
-		ZipArchive archive{BINARY "/output.zip", ZIP_CREATE};
-
-		archive.add(File{SOURCE "/data/data.txt"}, "data.txt");
-	} catch (const std::exception &ex) {
-		std::cerr << ex.what() << std::endl;
-	}
-
-	try {
-		ZipArchive archive{BINARY "/output.zip"};
-
-		auto stats = archive.stat("data.txt");
-		auto file = archive.open("data.txt");
-		auto content = file.read(stats.size);
-
-		ASSERT_EQ("abcdef\n", content);
-	} catch (const std::exception &ex) {
-		std::cerr << ex.what() << std::endl;
-	}
-}
-
-TEST(Source, buffer)
-{
-	remove(BINARY "/output.zip");
-
-	try {
-		ZipArchive archive{BINARY "/output.zip", ZIP_CREATE};
-
-		archive.add(Buffer{"abcdef"}, "data.txt");
-	} catch (const std::exception &ex) {
-		std::cerr << ex.what() << std::endl;
-	}
-
-	try {
-		ZipArchive archive{BINARY "/output.zip"};
-
-		auto stats = archive.stat("data.txt");
-		auto file = archive.open("data.txt");
-		auto content = file.read(stats.size);
-
-		ASSERT_EQ("abcdef", content);
-	} catch (const std::exception &ex) {
-		std::cerr << ex.what() << std::endl;
-	}
-}
-
-/* --------------------------------------------------------
- * Write
- * -------------------------------------------------------- */
-
-TEST(Write, simple)
-{
-	remove(BINARY "/output.zip");
-
-	// Open first and save some data
-	try {
-		ZipArchive archive{BINARY "/output.zip", ZIP_CREATE};
-
-		archive.add(Buffer{"hello world!"}, "DATA");
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-
-	try {
-		ZipArchive archive{BINARY "/output.zip"};
-
-		auto stats = archive.stat("DATA");
-		auto file = archive.open("DATA");
-		auto content = file.read(stats.size);
-
-		ASSERT_EQ(static_cast<decltype(stats.size)>(12), stats.size);
-		ASSERT_EQ("hello world!", content);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-/* --------------------------------------------------------
- * Reading
- * -------------------------------------------------------- */
-
-class ReadingTest : public testing::Test {
-protected:
-	ZipArchive m_archive;
-
-public:
-	ReadingTest()
-		: m_archive(SOURCE "/data/stats.zip")
-	{
-	}
-};
-
-TEST_F(ReadingTest, numEntries)
-{
-	ASSERT_EQ(static_cast<ZipInt64>(4), m_archive.numEntries());
-}
-
-TEST_F(ReadingTest, stat)
-{
-	try {
-		ZipStat stats = m_archive.stat("README");
-
-		ASSERT_EQ(static_cast<decltype(stats.size)>(15), stats.size);
-		ASSERT_STREQ("README", stats.name);
-	} catch (const std::exception &ex) {
-		std::cerr << ex.what() << std::endl;
-	}
-}
-
-TEST_F(ReadingTest, read)
-{
-	try {
-		auto file = m_archive.open("README");
-		auto stats = m_archive.stat("README");
-		auto text = file.read(stats.size);
-
-		ASSERT_EQ("This is a test\n", text);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-}
-
-TEST_F(ReadingTest, increment)
-{
-	{
-		ZipArchive::iterator it = m_archive.begin();
-
-		ASSERT_STREQ("README", (*it++).name);
-	}
-
-	{
-		ZipArchive::iterator it = m_archive.begin();
-
-		ASSERT_STREQ("INSTALL", (*++it).name);
-	}
-
-	{
-		ZipArchive::iterator it = m_archive.begin() + 1;
-
-		ASSERT_STREQ("INSTALL", (*it).name);
-	}
-}
-
-TEST_F(ReadingTest, decrement)
-{
-	{
-		ZipArchive::iterator it = m_archive.begin() + 1;
-
-		ASSERT_STREQ("INSTALL", (*it--).name);
-	}
-
-	{
-		ZipArchive::iterator it = m_archive.begin() + 1;
-
-		ASSERT_STREQ("README", (*--it).name);
-	}
-
-	{
-		ZipArchive::iterator it = m_archive.end() - 1;
-
-		ASSERT_STREQ("doc/REFMAN", (*it).name);
-	}
-}
-
-TEST_F(ReadingTest, constIncrement)
-{
-	{
-		ZipArchive::const_iterator it = m_archive.cbegin();
-
-		ASSERT_STREQ("README", (*it++).name);
-	}
-
-	{
-		ZipArchive::const_iterator it = m_archive.cbegin();
-
-		ASSERT_STREQ("INSTALL", (*++it).name);
-	}
-
-	{
-		ZipArchive::const_iterator it = m_archive.cbegin() + 1;
-
-		ASSERT_STREQ("INSTALL", (*it).name);
-	}
-}
-
-TEST_F(ReadingTest, constDecrement)
-{
-	{
-		ZipArchive::const_iterator it = m_archive.cbegin() + 1;
-
-		ASSERT_STREQ("INSTALL", (*it--).name);
-	}
-
-	{
-		ZipArchive::const_iterator it = m_archive.cbegin() + 1;
-
-		ASSERT_STREQ("README", (*--it).name);
-	}
-
-	{
-		ZipArchive::const_iterator it = m_archive.cend() - 1;
-
-		ASSERT_STREQ("doc/REFMAN", (*it).name);
-	}
-}
-
-TEST_F(ReadingTest, access)
-{
-	{
-		ZipArchive::iterator it = m_archive.begin();
-
-		ASSERT_STREQ("README", it->name);
-		ASSERT_STREQ("INSTALL", it[1].name);
-	}
-
-	{
-		ZipArchive::const_iterator it = m_archive.cbegin();
-
-		ASSERT_STREQ("README", it->name);
-		ASSERT_STREQ("INSTALL", it[1].name);
-	}
-}
-
-TEST_F(ReadingTest, loop)
-{
-	std::vector<std::string> names{"README", "INSTALL", "doc/", "doc/REFMAN"};
-	int i = 0;
-
-	for (const ZipStat &s : m_archive)
-		ASSERT_STREQ(names[i++].c_str(), s.name);
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/TreeNode.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,524 +0,0 @@
-/*
- * TreeNode.h -- C++11 pointer-free N-ary tree
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _TREE_NODE_H_
-#define _TREE_NODE_H_
-
-/**
- * @file TreeNode.h
- * @brief N-ary tree without pointers
- */
-
-#include <algorithm>
-#include <deque>
-#include <memory>
-#include <stdexcept>
-#include <type_traits>
-
-namespace {
-
-/**
- * @class TypeTraits
- * @brief Some checks on the type
- *
- * Provides the following members depending on the type:
- *
- *	equalityComparable	- If == comparison can be performed
- */
-template <typename T>
-class TypeTraits {
-private:
-	/**
-	 * @class HasEqualsTo
-	 * @brief Check if the type is comparable
-	 *
-	 * Sets to true if the type T can is equality comparable.
-	 */
-	template <typename U>
-	class HasEqualsTo {
-	public:
-		using Yes	= char [2];
-		using No	= char [1];
-
-		static_assert(sizeof (char) != sizeof (long), "buy a new compiler");
-
-		template <typename Value>
-		static constexpr Yes &check(Value *u, decltype(*u == *u) * = nullptr);
-
-		static constexpr No &check(...);
-
-		static constexpr const bool value = sizeof (check((U *)0)) == sizeof (Yes);
-	};
-
-public:
-	static constexpr const bool equalityComparable = HasEqualsTo<T>::value;
-};
-
-} // !namespace
-
-/**
- * @class TreeNode
- * @brief Safe C++11 N-ary tree
- *
- * This class use a std::deque as the container, it allocate object on the heap to avoid useless
- * copy and move when adding new elements.
- */
-template <typename T>
-class TreeNode {
-private:
-	class Object {
-	public:
-		virtual T &get() = 0;
-		virtual std::unique_ptr<Object> clone() const = 0;
-	};
-
-	template <typename Value>
-	struct Proxy final : public Object {
-	private:
-		Value m_value;
-
-		Proxy(const Proxy &) = delete;
-		Proxy &operator=(const Proxy &) = delete;
-		Proxy(Proxy &&) = delete;
-		Proxy &operator=(Proxy &&) = delete;
-
-	public:
-		inline Proxy(Value &&value)
-			: m_value(std::move(value))
-		{
-		}
-
-		inline Proxy(const Value &value)
-			: m_value(value)
-		{
-		}
-
-		template <typename... Args>
-		inline Proxy(Args&&... args)
-			: m_value(std::forward<Args>(args)...)
-		{
-		}
-
-		T &get() override
-		{
-			return m_value;
-		}
-
-		std::unique_ptr<Object> clone() const override
-		{
-			return std::make_unique<Proxy<Value>>(m_value);
-		}	
-	};
-
-	using Container	= std::deque<std::unique_ptr<Object>>;
-
-	TreeNode	*m_parent{nullptr};
-	Container	 m_children;
-
-public:
-	/**
-	 * Default constructor.
-	 */
-	TreeNode() = default;
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~TreeNode() = default;
-
-	/**
-	 * Copy constructor.
-	 *
-	 * @param other the other node
-	 */
-	TreeNode(const TreeNode &other)
-		: m_parent(nullptr)
-	{
-		for (const auto &c : other.m_children) {
-			m_children.push_back(c->clone());
-			m_children.back()->get().m_parent = this;
-		}
-	}
-
-	/**
-	 * Move constructor.
-	 *
-	 * @param other the other node
-	 */
-	TreeNode(TreeNode &&other)
-		: m_parent(nullptr)
-		, m_children(std::move(other.m_children))
-	{
-		// Update children to update to *this
-		for (auto &c : m_children)
-			c->get().m_parent = this;
-
-		other.m_children.clear();
-	}
-
-	/**
-	 * Copy assignment operator.
-	 *
-	 * @param other the other node
-	 */
-	TreeNode &operator=(const TreeNode &other)
-	{
-		m_children.clear();
-
-		for (const auto &c : other.m_children) {
-			m_children.push_back(c->clone());
-			m_children.back()->get().m_parent = this;
-		}
-
-		return *this;
-	}
-
-	/**
-	 * Move assignment operator.
-	 *
-	 * @param other the other node
-	 */
-	TreeNode &operator=(TreeNode &&other)
-	{
-		m_children = std::move(other.m_children);
-
-		// Update children to update to *this
-		for (auto &c : m_children)
-			c->get().m_parent = this;
-
-		other.m_children.clear();
-
-		return *this;
-	}
-
-	/**
-	 * Add a child node to the beginning.
-	 *
-	 * @param child the children
-	 */
-	template <typename Value>
-	inline void push(const Value &child)
-	{
-		m_children.push_front(std::make_unique<Proxy<Value>>(child));
-		m_children.front()->get().m_parent = this;
-	}
-
-	/**
-	 * Move to the beginning.
-	 *
-	 * @param child the children
-	 */
-	template <typename Value>
-	inline void push(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value>::type * = nullptr)
-	{
-		using Type = typename std::decay<Value>::type;
-
-		m_children.push_front(std::make_unique<Proxy<Type>>(std::move(child)));
-		m_children.front()->get().m_parent = this;
-	}
-
-	/**
-	 * Construct an element at the beginning in place.
-	 *
-	 * @param args the arguments
-	 */
-	template <typename... Args>
-	void pushNew(Args&&... args)
-	{
-		m_children.emplace_front(std::make_unique<Proxy<T>>(std::forward<Args>(args)...));
-		m_children.front()->get().m_parent = this;
-	}
-
-	/**
-	 * Add a child node to the end
-	 *
-	 * @param child the children
-	 */
-	template <typename Value>
-	inline void append(const Value &child)
-	{
-		m_children.push_back(std::make_unique<Proxy<Value>>(child));
-		m_children.back()->get().m_parent = this;
-	}
-
-	/**
-	 * Move a child node to the end
-	 *
-	 * @param child the children
-	 */
-	template <typename Value>
-	inline void append(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value>::type * = nullptr)
-	{
-		using Type = typename std::decay<Value>::type;
-
-		m_children.push_back(std::make_unique<Proxy<Type>>(std::move(child)));
-		m_children.back()->get().m_parent = this;
-	}
-
-	/**
-	 * Construct an element at the end in place.
-	 *
-	 * @param args the arguments
-	 */
-	template <typename... Args>
-	void appendNew(Args&&... args)
-	{
-		m_children.emplace_back(std::make_unique<Proxy<T>>(std::forward<Args>(args)...));
-		m_children.back()->get().m_parent = this;
-	}
-
-	/**
-	 * Count the number of children in this node.
-	 *
-	 * @return the number of children
-	 */
-	unsigned countChildren() const noexcept
-	{
-		return static_cast<unsigned>(m_children.size());
-	}
-
-	/**
-	 * Get the parent node.
-	 *
-	 * @return the parent node
-	 * @throw std::out_of_range if there is no parent
-	 */
-	T &parent()
-	{
-		if (!m_parent)
-			throw std::out_of_range("no parent");
-
-		return static_cast<T &>(*m_parent);
-	}
-
-	/**
-	 * Get the parent node.
-	 *
-	 * @return the parent node
-	 * @throw std::out_of_range if there is no parent
-	 */
-	const T &parent() const
-	{
-		if (!m_parent)
-			throw std::out_of_range("no parent");
-
-		return static_cast<const T &>(*m_parent);
-	}
-
-	/**
-	 * Check if the node is root (no parent).
-	 *
-	 * @return true if root
-	 */
-	bool isRoot() const noexcept
-	{
-		return m_parent == nullptr;
-	}
-
-	/**
-	 * Check if the node is leaf (no children).
-	 *
-	 * @return true if leaf
-	 */
-	bool isLeaf() const noexcept
-	{
-		return m_children.size() == 0;
-	}
-
-	/**
-	 * Remove a child from the node at the given index.
-	 *
-	 * @param index the position index
-	 * @throw std::out_of_range if index is out of bounds
-	 */
-	void remove(int index)
-	{
-		if (index < 0 || index >= m_children.size())
-			throw std::out_of_range("index is out of range");
-
-		m_children.erase(m_children.begin() + index);
-	}
-
-	/**
-	 * Remove a child from the node, the child must exists and no comparison test is performed, only
-	 * object addresses are compared.
-	 *
-	 * @param value the value that exists in the node
-	 * @warn the removed object must not be used after the call
-	 */
-	void remove(T &value)
-	{
-		m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&] (auto &p) {
-			return &p->get() == &value;
-		}), m_children.end());
-	}
-
-	/**
-	 * Remove a child from the node, the value is tested using operator== and therefore may not exist in the container.
-	 *
-	 * @param value the value that can be compared
-	 * @warn the removed object must not be used after the call
-	 */
-	template <typename Value>
-	void removeSame(const Value &value, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr)
-	{
-		m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&] (auto &p) {
-			return p->get() == value;
-		}), m_children.end());
-	}
-
-	/**
-	 * Remove all children.
-	 */
-	void clear()
-	{
-		m_children.clear();
-	}
-
-	/**
-	 * Find a child in this node, the child address is used as the comparison so no equality operator is even called.
-	 *
-	 * @param child the child
-	 * @return the index or -1 if not found
-	 * @see indexOfSame
-	 */
-	int indexOf(const T &child) const noexcept
-	{
-		for (unsigned i = 0; i < m_children.size(); ++i)
-			if (&m_children[i]->get() == &child)
-				return i;
-
-		return -1;
-	}
-
-	/**
-	 * Find the index of a node that is equality comparable to value but may be not in the node.
-	 *
-	 * @param value the value to compare
-	 * @return the index or -1 if not found
-	 * @see indexOf
-	 */
-	template <typename Value>
-	int indexOfSame(const Value &value, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr) const noexcept
-	{
-		for (unsigned i = 0; i < m_children.size(); ++i)
-			if (m_children[i]->get() == value)
-				return i;
-
-		return -1;
-	}
-
-	/**
-	 * Iterate over all the nodes. The first node is also passed through
-	 * the callback.
-	 *
-	 * @param callback the callback
-	 */
-	template <typename Callback>
-	void map(Callback callback)
-	{
-		callback(static_cast<T &>(*this));
-
-		for (auto &v : m_children)
-			v->get().map(callback);
-	}
-
-	/**
-	 * Convert the tree to a flat list by appending to the output iterator.
-	 *
-	 * @param dest the destination iterator
-	 */
-	template <typename OutputIt>
-	void flat(OutputIt dest)
-	{
-		map([&] (const auto &value) {
-			*dest++ = value;
-		});
-	}
-
-	/**
-	 * Iterate all values and call the function when found.
-	 *
-	 * @param predicate the predicate
-	 * @param callable the callable to call when found
-	 * @return true if found
-	 */
-	template <typename UnaryPredicate, typename Callable>
-	bool search(UnaryPredicate predicate, Callable callable)
-	{
-		if (predicate(static_cast<const T &>(*this))) {
-			callable(static_cast<T &>(*this));
-			return true;
-		}
-
-		for (auto &v : m_children) {
-			if (v->get().search(predicate, callable))
-				return true;
-		}
-
-		return false;
-	}
-
-	/**
-	 * Search and return the first value matching the predicate.
-	 *
-	 * @param predicate the predicate
-	 * @return the reference to the node
-	 * @throw std::out_of_range if not found
-	 */
-	template <typename UnaryPredicate>
-	T &search(UnaryPredicate predicate)
-	{
-		T *value{nullptr};
-
-		search(predicate, [&] (auto &ptr) {
-			value = &ptr;
-		});
-
-		if (value == nullptr)
-			throw std::out_of_range("node not found");
-
-		return *value;
-	}
-
-	/**
-	 * Access a child.
-	 *
-	 * @param index the index
-	 * @return the reference to the children node
-	 * @throw std::out_of_range on out of bounds
-	 */
-	T &operator[](int index)
-	{
-		return static_cast<T &>(m_children.at(index)->get());
-	}
-
-	/**
-	 * Access a child.
-	 *
-	 * @param index the index
-	 * @return the reference to the children node
-	 * @throw std::out_of_range on out of bounds
-	 */
-	const T &operator[](int index) const
-	{
-		return static_cast<const T &>(m_children.at(index)->get());
-	}
-};
-
-#endif // !_TREE_NODE_H_
--- a/C++/Utf8.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4619 +0,0 @@
-/*
- * Utf8.cpp -- UTF-8 to UTF-32 conversions
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "Utf8.h"
-
-namespace {
-
-#define LEN(x)	(sizeof (x) / sizeof (x[0]))
-
-static uint32_t *
-rbsearch(uint32_t c, uint32_t *t, int n, int ne)
-{
-	uint32_t *p;
-	int m;
-
-	while (n > 1) {
-		m = n >> 1;
-		p = t + m * ne;
-
-		if (c >= p[0]) {
-			t = p;
-			n = n - m;
-		} else
-			n = m;
-	}
-
-	if (n && c >= t[0])
-		return t;
-	return 0;
-}
-
-/*
- * The following values have been generated from Go mkrunetype.c
- *
- * http://golang.org/src/lib9/utf/mkrunetype.c
- */
-
-/* {{{ Spaces */
-
-static uint32_t isspacer[] = {
-	0x0009, 0x000d,
-	0x0020, 0x0020,
-	0x0085, 0x0085,
-	0x00a0, 0x00a0,
-	0x1680, 0x1680,
-	0x2000, 0x200a,
-	0x2028, 0x2029,
-	0x202f, 0x202f,
-	0x205f, 0x205f,
-	0x3000, 0x3000,
-	0xfeff, 0xfeff,
-};
-
-/* }}} */
-
-/* {{{ Digits */
-
-static uint32_t isdigitr[] = {
-	0x0030, 0x0039,
-	0x0660, 0x0669,
-	0x06f0, 0x06f9,
-	0x07c0, 0x07c9,
-	0x0966, 0x096f,
-	0x09e6, 0x09ef,
-	0x0a66, 0x0a6f,
-	0x0ae6, 0x0aef,
-	0x0b66, 0x0b6f,
-	0x0be6, 0x0bef,
-	0x0c66, 0x0c6f,
-	0x0ce6, 0x0cef,
-	0x0d66, 0x0d6f,
-	0x0e50, 0x0e59,
-	0x0ed0, 0x0ed9,
-	0x0f20, 0x0f29,
-	0x1040, 0x1049,
-	0x1090, 0x1099,
-	0x17e0, 0x17e9,
-	0x1810, 0x1819,
-	0x1946, 0x194f,
-	0x19d0, 0x19d9,
-	0x1a80, 0x1a89,
-	0x1a90, 0x1a99,
-	0x1b50, 0x1b59,
-	0x1bb0, 0x1bb9,
-	0x1c40, 0x1c49,
-	0x1c50, 0x1c59,
-	0xa620, 0xa629,
-	0xa8d0, 0xa8d9,
-	0xa900, 0xa909,
-	0xa9d0, 0xa9d9,
-	0xaa50, 0xaa59,
-	0xabf0, 0xabf9,
-	0xff10, 0xff19,
-	0x104a0, 0x104a9,
-	0x11066, 0x1106f,
-	0x110f0, 0x110f9,
-	0x11136, 0x1113f,
-	0x111d0, 0x111d9,
-	0x116c0, 0x116c9,
-	0x1d7ce, 0x1d7ff,
-};
-
-/* }}} */
-
-/* {{{ Unicode letters */
-
-static uint32_t isalphar[] = {
-	0x0041, 0x005a,
-	0x0061, 0x007a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00f6,
-	0x00f8, 0x02c1,
-	0x02c6, 0x02d1,
-	0x02e0, 0x02e4,
-	0x0370, 0x0374,
-	0x0376, 0x0377,
-	0x037a, 0x037d,
-	0x0388, 0x038a,
-	0x038e, 0x03a1,
-	0x03a3, 0x03f5,
-	0x03f7, 0x0481,
-	0x048a, 0x0527,
-	0x0531, 0x0556,
-	0x0561, 0x0587,
-	0x05d0, 0x05ea,
-	0x05f0, 0x05f2,
-	0x0620, 0x064a,
-	0x066e, 0x066f,
-	0x0671, 0x06d3,
-	0x06e5, 0x06e6,
-	0x06ee, 0x06ef,
-	0x06fa, 0x06fc,
-	0x0712, 0x072f,
-	0x074d, 0x07a5,
-	0x07ca, 0x07ea,
-	0x07f4, 0x07f5,
-	0x0800, 0x0815,
-	0x0840, 0x0858,
-	0x08a2, 0x08ac,
-	0x0904, 0x0939,
-	0x0958, 0x0961,
-	0x0971, 0x0977,
-	0x0979, 0x097f,
-	0x0985, 0x098c,
-	0x098f, 0x0990,
-	0x0993, 0x09a8,
-	0x09aa, 0x09b0,
-	0x09b6, 0x09b9,
-	0x09dc, 0x09dd,
-	0x09df, 0x09e1,
-	0x09f0, 0x09f1,
-	0x0a05, 0x0a0a,
-	0x0a0f, 0x0a10,
-	0x0a13, 0x0a28,
-	0x0a2a, 0x0a30,
-	0x0a32, 0x0a33,
-	0x0a35, 0x0a36,
-	0x0a38, 0x0a39,
-	0x0a59, 0x0a5c,
-	0x0a72, 0x0a74,
-	0x0a85, 0x0a8d,
-	0x0a8f, 0x0a91,
-	0x0a93, 0x0aa8,
-	0x0aaa, 0x0ab0,
-	0x0ab2, 0x0ab3,
-	0x0ab5, 0x0ab9,
-	0x0ae0, 0x0ae1,
-	0x0b05, 0x0b0c,
-	0x0b0f, 0x0b10,
-	0x0b13, 0x0b28,
-	0x0b2a, 0x0b30,
-	0x0b32, 0x0b33,
-	0x0b35, 0x0b39,
-	0x0b5c, 0x0b5d,
-	0x0b5f, 0x0b61,
-	0x0b85, 0x0b8a,
-	0x0b8e, 0x0b90,
-	0x0b92, 0x0b95,
-	0x0b99, 0x0b9a,
-	0x0b9e, 0x0b9f,
-	0x0ba3, 0x0ba4,
-	0x0ba8, 0x0baa,
-	0x0bae, 0x0bb9,
-	0x0c05, 0x0c0c,
-	0x0c0e, 0x0c10,
-	0x0c12, 0x0c28,
-	0x0c2a, 0x0c33,
-	0x0c35, 0x0c39,
-	0x0c58, 0x0c59,
-	0x0c60, 0x0c61,
-	0x0c85, 0x0c8c,
-	0x0c8e, 0x0c90,
-	0x0c92, 0x0ca8,
-	0x0caa, 0x0cb3,
-	0x0cb5, 0x0cb9,
-	0x0ce0, 0x0ce1,
-	0x0cf1, 0x0cf2,
-	0x0d05, 0x0d0c,
-	0x0d0e, 0x0d10,
-	0x0d12, 0x0d3a,
-	0x0d60, 0x0d61,
-	0x0d7a, 0x0d7f,
-	0x0d85, 0x0d96,
-	0x0d9a, 0x0db1,
-	0x0db3, 0x0dbb,
-	0x0dc0, 0x0dc6,
-	0x0e01, 0x0e30,
-	0x0e32, 0x0e33,
-	0x0e40, 0x0e46,
-	0x0e81, 0x0e82,
-	0x0e87, 0x0e88,
-	0x0e94, 0x0e97,
-	0x0e99, 0x0e9f,
-	0x0ea1, 0x0ea3,
-	0x0eaa, 0x0eab,
-	0x0ead, 0x0eb0,
-	0x0eb2, 0x0eb3,
-	0x0ec0, 0x0ec4,
-	0x0edc, 0x0edf,
-	0x0f40, 0x0f47,
-	0x0f49, 0x0f6c,
-	0x0f88, 0x0f8c,
-	0x1000, 0x102a,
-	0x1050, 0x1055,
-	0x105a, 0x105d,
-	0x1065, 0x1066,
-	0x106e, 0x1070,
-	0x1075, 0x1081,
-	0x10a0, 0x10c5,
-	0x10d0, 0x10fa,
-	0x10fc, 0x1248,
-	0x124a, 0x124d,
-	0x1250, 0x1256,
-	0x125a, 0x125d,
-	0x1260, 0x1288,
-	0x128a, 0x128d,
-	0x1290, 0x12b0,
-	0x12b2, 0x12b5,
-	0x12b8, 0x12be,
-	0x12c2, 0x12c5,
-	0x12c8, 0x12d6,
-	0x12d8, 0x1310,
-	0x1312, 0x1315,
-	0x1318, 0x135a,
-	0x1380, 0x138f,
-	0x13a0, 0x13f4,
-	0x1401, 0x166c,
-	0x166f, 0x167f,
-	0x1681, 0x169a,
-	0x16a0, 0x16ea,
-	0x1700, 0x170c,
-	0x170e, 0x1711,
-	0x1720, 0x1731,
-	0x1740, 0x1751,
-	0x1760, 0x176c,
-	0x176e, 0x1770,
-	0x1780, 0x17b3,
-	0x1820, 0x1877,
-	0x1880, 0x18a8,
-	0x18b0, 0x18f5,
-	0x1900, 0x191c,
-	0x1950, 0x196d,
-	0x1970, 0x1974,
-	0x1980, 0x19ab,
-	0x19c1, 0x19c7,
-	0x1a00, 0x1a16,
-	0x1a20, 0x1a54,
-	0x1b05, 0x1b33,
-	0x1b45, 0x1b4b,
-	0x1b83, 0x1ba0,
-	0x1bae, 0x1baf,
-	0x1bba, 0x1be5,
-	0x1c00, 0x1c23,
-	0x1c4d, 0x1c4f,
-	0x1c5a, 0x1c7d,
-	0x1ce9, 0x1cec,
-	0x1cee, 0x1cf1,
-	0x1cf5, 0x1cf6,
-	0x1d00, 0x1dbf,
-	0x1e00, 0x1f15,
-	0x1f18, 0x1f1d,
-	0x1f20, 0x1f45,
-	0x1f48, 0x1f4d,
-	0x1f50, 0x1f57,
-	0x1f5f, 0x1f7d,
-	0x1f80, 0x1fb4,
-	0x1fb6, 0x1fbc,
-	0x1fc2, 0x1fc4,
-	0x1fc6, 0x1fcc,
-	0x1fd0, 0x1fd3,
-	0x1fd6, 0x1fdb,
-	0x1fe0, 0x1fec,
-	0x1ff2, 0x1ff4,
-	0x1ff6, 0x1ffc,
-	0x2090, 0x209c,
-	0x210a, 0x2113,
-	0x2119, 0x211d,
-	0x212a, 0x212d,
-	0x212f, 0x2139,
-	0x213c, 0x213f,
-	0x2145, 0x2149,
-	0x2183, 0x2184,
-	0x2c00, 0x2c2e,
-	0x2c30, 0x2c5e,
-	0x2c60, 0x2ce4,
-	0x2ceb, 0x2cee,
-	0x2cf2, 0x2cf3,
-	0x2d00, 0x2d25,
-	0x2d30, 0x2d67,
-	0x2d80, 0x2d96,
-	0x2da0, 0x2da6,
-	0x2da8, 0x2dae,
-	0x2db0, 0x2db6,
-	0x2db8, 0x2dbe,
-	0x2dc0, 0x2dc6,
-	0x2dc8, 0x2dce,
-	0x2dd0, 0x2dd6,
-	0x2dd8, 0x2dde,
-	0x3005, 0x3006,
-	0x3031, 0x3035,
-	0x303b, 0x303c,
-	0x3041, 0x3096,
-	0x309d, 0x309f,
-	0x30a1, 0x30fa,
-	0x30fc, 0x30ff,
-	0x3105, 0x312d,
-	0x3131, 0x318e,
-	0x31a0, 0x31ba,
-	0x31f0, 0x31ff,
-	0x3400, 0x4db5,
-	0x4e00, 0x9fcc,
-	0xa000, 0xa48c,
-	0xa4d0, 0xa4fd,
-	0xa500, 0xa60c,
-	0xa610, 0xa61f,
-	0xa62a, 0xa62b,
-	0xa640, 0xa66e,
-	0xa67f, 0xa697,
-	0xa6a0, 0xa6e5,
-	0xa717, 0xa71f,
-	0xa722, 0xa788,
-	0xa78b, 0xa78e,
-	0xa790, 0xa793,
-	0xa7a0, 0xa7aa,
-	0xa7f8, 0xa801,
-	0xa803, 0xa805,
-	0xa807, 0xa80a,
-	0xa80c, 0xa822,
-	0xa840, 0xa873,
-	0xa882, 0xa8b3,
-	0xa8f2, 0xa8f7,
-	0xa90a, 0xa925,
-	0xa930, 0xa946,
-	0xa960, 0xa97c,
-	0xa984, 0xa9b2,
-	0xaa00, 0xaa28,
-	0xaa40, 0xaa42,
-	0xaa44, 0xaa4b,
-	0xaa60, 0xaa76,
-	0xaa80, 0xaaaf,
-	0xaab5, 0xaab6,
-	0xaab9, 0xaabd,
-	0xaadb, 0xaadd,
-	0xaae0, 0xaaea,
-	0xaaf2, 0xaaf4,
-	0xab01, 0xab06,
-	0xab09, 0xab0e,
-	0xab11, 0xab16,
-	0xab20, 0xab26,
-	0xab28, 0xab2e,
-	0xabc0, 0xabe2,
-	0xac00, 0xd7a3,
-	0xd7b0, 0xd7c6,
-	0xd7cb, 0xd7fb,
-	0xf900, 0xfa6d,
-	0xfa70, 0xfad9,
-	0xfb00, 0xfb06,
-	0xfb13, 0xfb17,
-	0xfb1f, 0xfb28,
-	0xfb2a, 0xfb36,
-	0xfb38, 0xfb3c,
-	0xfb40, 0xfb41,
-	0xfb43, 0xfb44,
-	0xfb46, 0xfbb1,
-	0xfbd3, 0xfd3d,
-	0xfd50, 0xfd8f,
-	0xfd92, 0xfdc7,
-	0xfdf0, 0xfdfb,
-	0xfe70, 0xfe74,
-	0xfe76, 0xfefc,
-	0xff21, 0xff3a,
-	0xff41, 0xff5a,
-	0xff66, 0xffbe,
-	0xffc2, 0xffc7,
-	0xffca, 0xffcf,
-	0xffd2, 0xffd7,
-	0xffda, 0xffdc,
-	0x10000, 0x1000b,
-	0x1000d, 0x10026,
-	0x10028, 0x1003a,
-	0x1003c, 0x1003d,
-	0x1003f, 0x1004d,
-	0x10050, 0x1005d,
-	0x10080, 0x100fa,
-	0x10280, 0x1029c,
-	0x102a0, 0x102d0,
-	0x10300, 0x1031e,
-	0x10330, 0x10340,
-	0x10342, 0x10349,
-	0x10380, 0x1039d,
-	0x103a0, 0x103c3,
-	0x103c8, 0x103cf,
-	0x10400, 0x1049d,
-	0x10800, 0x10805,
-	0x1080a, 0x10835,
-	0x10837, 0x10838,
-	0x1083f, 0x10855,
-	0x10900, 0x10915,
-	0x10920, 0x10939,
-	0x10980, 0x109b7,
-	0x109be, 0x109bf,
-	0x10a10, 0x10a13,
-	0x10a15, 0x10a17,
-	0x10a19, 0x10a33,
-	0x10a60, 0x10a7c,
-	0x10b00, 0x10b35,
-	0x10b40, 0x10b55,
-	0x10b60, 0x10b72,
-	0x10c00, 0x10c48,
-	0x11003, 0x11037,
-	0x11083, 0x110af,
-	0x110d0, 0x110e8,
-	0x11103, 0x11126,
-	0x11183, 0x111b2,
-	0x111c1, 0x111c4,
-	0x11680, 0x116aa,
-	0x12000, 0x1236e,
-	0x13000, 0x1342e,
-	0x16800, 0x16a38,
-	0x16f00, 0x16f44,
-	0x16f93, 0x16f9f,
-	0x1b000, 0x1b001,
-	0x1d400, 0x1d454,
-	0x1d456, 0x1d49c,
-	0x1d49e, 0x1d49f,
-	0x1d4a5, 0x1d4a6,
-	0x1d4a9, 0x1d4ac,
-	0x1d4ae, 0x1d4b9,
-	0x1d4bd, 0x1d4c3,
-	0x1d4c5, 0x1d505,
-	0x1d507, 0x1d50a,
-	0x1d50d, 0x1d514,
-	0x1d516, 0x1d51c,
-	0x1d51e, 0x1d539,
-	0x1d53b, 0x1d53e,
-	0x1d540, 0x1d544,
-	0x1d54a, 0x1d550,
-	0x1d552, 0x1d6a5,
-	0x1d6a8, 0x1d6c0,
-	0x1d6c2, 0x1d6da,
-	0x1d6dc, 0x1d6fa,
-	0x1d6fc, 0x1d714,
-	0x1d716, 0x1d734,
-	0x1d736, 0x1d74e,
-	0x1d750, 0x1d76e,
-	0x1d770, 0x1d788,
-	0x1d78a, 0x1d7a8,
-	0x1d7aa, 0x1d7c2,
-	0x1d7c4, 0x1d7cb,
-	0x1ee00, 0x1ee03,
-	0x1ee05, 0x1ee1f,
-	0x1ee21, 0x1ee22,
-	0x1ee29, 0x1ee32,
-	0x1ee34, 0x1ee37,
-	0x1ee4d, 0x1ee4f,
-	0x1ee51, 0x1ee52,
-	0x1ee61, 0x1ee62,
-	0x1ee67, 0x1ee6a,
-	0x1ee6c, 0x1ee72,
-	0x1ee74, 0x1ee77,
-	0x1ee79, 0x1ee7c,
-	0x1ee80, 0x1ee89,
-	0x1ee8b, 0x1ee9b,
-	0x1eea1, 0x1eea3,
-	0x1eea5, 0x1eea9,
-	0x1eeab, 0x1eebb,
-	0x20000, 0x2a6d6,
-	0x2a700, 0x2b734,
-	0x2b740, 0x2b81d,
-	0x2f800, 0x2fa1d,
-};
-
-/* }}} */
-
-/* {{{ Letters */
-
-static uint32_t isalphas[] = {
-	0x00aa,
-	0x00b5,
-	0x00ba,
-	0x02ec,
-	0x02ee,
-	0x0386,
-	0x038c,
-	0x0559,
-	0x06d5,
-	0x06ff,
-	0x0710,
-	0x07b1,
-	0x07fa,
-	0x081a,
-	0x0824,
-	0x0828,
-	0x08a0,
-	0x093d,
-	0x0950,
-	0x09b2,
-	0x09bd,
-	0x09ce,
-	0x0a5e,
-	0x0abd,
-	0x0ad0,
-	0x0b3d,
-	0x0b71,
-	0x0b83,
-	0x0b9c,
-	0x0bd0,
-	0x0c3d,
-	0x0cbd,
-	0x0cde,
-	0x0d3d,
-	0x0d4e,
-	0x0dbd,
-	0x0e84,
-	0x0e8a,
-	0x0e8d,
-	0x0ea5,
-	0x0ea7,
-	0x0ebd,
-	0x0ec6,
-	0x0f00,
-	0x103f,
-	0x1061,
-	0x108e,
-	0x10c7,
-	0x10cd,
-	0x1258,
-	0x12c0,
-	0x17d7,
-	0x17dc,
-	0x18aa,
-	0x1aa7,
-	0x1f59,
-	0x1f5b,
-	0x1f5d,
-	0x1fbe,
-	0x2071,
-	0x207f,
-	0x2102,
-	0x2107,
-	0x2115,
-	0x2124,
-	0x2126,
-	0x2128,
-	0x214e,
-	0x2d27,
-	0x2d2d,
-	0x2d6f,
-	0x2e2f,
-	0xa8fb,
-	0xa9cf,
-	0xaa7a,
-	0xaab1,
-	0xaac0,
-	0xaac2,
-	0xfb1d,
-	0xfb3e,
-	0x10808,
-	0x1083c,
-	0x10a00,
-	0x16f50,
-	0x1d4a2,
-	0x1d4bb,
-	0x1d546,
-	0x1ee24,
-	0x1ee27,
-	0x1ee39,
-	0x1ee3b,
-	0x1ee42,
-	0x1ee47,
-	0x1ee49,
-	0x1ee4b,
-	0x1ee54,
-	0x1ee57,
-	0x1ee59,
-	0x1ee5b,
-	0x1ee5d,
-	0x1ee5f,
-	0x1ee64,
-	0x1ee7e,
-};
-
-/* }}} */
-
-/* {{{ Unicode upper */
-
-static uint32_t isupperr[] = {
-	0x0041, 0x005a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00de,
-	0x0178, 0x0179,
-	0x0181, 0x0182,
-	0x0186, 0x0187,
-	0x0189, 0x018b,
-	0x018e, 0x0191,
-	0x0193, 0x0194,
-	0x0196, 0x0198,
-	0x019c, 0x019d,
-	0x019f, 0x01a0,
-	0x01a6, 0x01a7,
-	0x01ae, 0x01af,
-	0x01b1, 0x01b3,
-	0x01b7, 0x01b8,
-	0x01f6, 0x01f8,
-	0x023a, 0x023b,
-	0x023d, 0x023e,
-	0x0243, 0x0246,
-	0x0388, 0x038a,
-	0x038e, 0x038f,
-	0x0391, 0x03a1,
-	0x03a3, 0x03ab,
-	0x03d2, 0x03d4,
-	0x03f9, 0x03fa,
-	0x03fd, 0x042f,
-	0x04c0, 0x04c1,
-	0x0531, 0x0556,
-	0x10a0, 0x10c5,
-	0x1f08, 0x1f0f,
-	0x1f18, 0x1f1d,
-	0x1f28, 0x1f2f,
-	0x1f38, 0x1f3f,
-	0x1f48, 0x1f4d,
-	0x1f68, 0x1f6f,
-	0x1f88, 0x1f8f,
-	0x1f98, 0x1f9f,
-	0x1fa8, 0x1faf,
-	0x1fb8, 0x1fbc,
-	0x1fc8, 0x1fcc,
-	0x1fd8, 0x1fdb,
-	0x1fe8, 0x1fec,
-	0x1ff8, 0x1ffc,
-	0x210b, 0x210d,
-	0x2110, 0x2112,
-	0x2119, 0x211d,
-	0x212a, 0x212d,
-	0x2130, 0x2133,
-	0x213e, 0x213f,
-	0x2160, 0x216f,
-	0x24b6, 0x24cf,
-	0x2c00, 0x2c2e,
-	0x2c62, 0x2c64,
-	0x2c6d, 0x2c70,
-	0x2c7e, 0x2c80,
-	0xa77d, 0xa77e,
-	0xff21, 0xff3a,
-	0x10400, 0x10427,
-	0x1d400, 0x1d419,
-	0x1d434, 0x1d44d,
-	0x1d468, 0x1d481,
-	0x1d49e, 0x1d49f,
-	0x1d4a5, 0x1d4a6,
-	0x1d4a9, 0x1d4ac,
-	0x1d4ae, 0x1d4b5,
-	0x1d4d0, 0x1d4e9,
-	0x1d504, 0x1d505,
-	0x1d507, 0x1d50a,
-	0x1d50d, 0x1d514,
-	0x1d516, 0x1d51c,
-	0x1d538, 0x1d539,
-	0x1d53b, 0x1d53e,
-	0x1d540, 0x1d544,
-	0x1d54a, 0x1d550,
-	0x1d56c, 0x1d585,
-	0x1d5a0, 0x1d5b9,
-	0x1d5d4, 0x1d5ed,
-	0x1d608, 0x1d621,
-	0x1d63c, 0x1d655,
-	0x1d670, 0x1d689,
-	0x1d6a8, 0x1d6c0,
-	0x1d6e2, 0x1d6fa,
-	0x1d71c, 0x1d734,
-	0x1d756, 0x1d76e,
-	0x1d790, 0x1d7a8,
-};
-
-/* }}} */
-
-/* {{{ Upper */
-
-static uint32_t isuppers[] = {
-	0x0100,
-	0x0102,
-	0x0104,
-	0x0106,
-	0x0108,
-	0x010a,
-	0x010c,
-	0x010e,
-	0x0110,
-	0x0112,
-	0x0114,
-	0x0116,
-	0x0118,
-	0x011a,
-	0x011c,
-	0x011e,
-	0x0120,
-	0x0122,
-	0x0124,
-	0x0126,
-	0x0128,
-	0x012a,
-	0x012c,
-	0x012e,
-	0x0130,
-	0x0132,
-	0x0134,
-	0x0136,
-	0x0139,
-	0x013b,
-	0x013d,
-	0x013f,
-	0x0141,
-	0x0143,
-	0x0145,
-	0x0147,
-	0x014a,
-	0x014c,
-	0x014e,
-	0x0150,
-	0x0152,
-	0x0154,
-	0x0156,
-	0x0158,
-	0x015a,
-	0x015c,
-	0x015e,
-	0x0160,
-	0x0162,
-	0x0164,
-	0x0166,
-	0x0168,
-	0x016a,
-	0x016c,
-	0x016e,
-	0x0170,
-	0x0172,
-	0x0174,
-	0x0176,
-	0x017b,
-	0x017d,
-	0x0184,
-	0x01a2,
-	0x01a4,
-	0x01a9,
-	0x01ac,
-	0x01b5,
-	0x01bc,
-	0x01c4,
-	0x01c7,
-	0x01ca,
-	0x01cd,
-	0x01cf,
-	0x01d1,
-	0x01d3,
-	0x01d5,
-	0x01d7,
-	0x01d9,
-	0x01db,
-	0x01de,
-	0x01e0,
-	0x01e2,
-	0x01e4,
-	0x01e6,
-	0x01e8,
-	0x01ea,
-	0x01ec,
-	0x01ee,
-	0x01f1,
-	0x01f4,
-	0x01fa,
-	0x01fc,
-	0x01fe,
-	0x0200,
-	0x0202,
-	0x0204,
-	0x0206,
-	0x0208,
-	0x020a,
-	0x020c,
-	0x020e,
-	0x0210,
-	0x0212,
-	0x0214,
-	0x0216,
-	0x0218,
-	0x021a,
-	0x021c,
-	0x021e,
-	0x0220,
-	0x0222,
-	0x0224,
-	0x0226,
-	0x0228,
-	0x022a,
-	0x022c,
-	0x022e,
-	0x0230,
-	0x0232,
-	0x0241,
-	0x0248,
-	0x024a,
-	0x024c,
-	0x024e,
-	0x0370,
-	0x0372,
-	0x0376,
-	0x0386,
-	0x038c,
-	0x03cf,
-	0x03d8,
-	0x03da,
-	0x03dc,
-	0x03de,
-	0x03e0,
-	0x03e2,
-	0x03e4,
-	0x03e6,
-	0x03e8,
-	0x03ea,
-	0x03ec,
-	0x03ee,
-	0x03f4,
-	0x03f7,
-	0x0460,
-	0x0462,
-	0x0464,
-	0x0466,
-	0x0468,
-	0x046a,
-	0x046c,
-	0x046e,
-	0x0470,
-	0x0472,
-	0x0474,
-	0x0476,
-	0x0478,
-	0x047a,
-	0x047c,
-	0x047e,
-	0x0480,
-	0x048a,
-	0x048c,
-	0x048e,
-	0x0490,
-	0x0492,
-	0x0494,
-	0x0496,
-	0x0498,
-	0x049a,
-	0x049c,
-	0x049e,
-	0x04a0,
-	0x04a2,
-	0x04a4,
-	0x04a6,
-	0x04a8,
-	0x04aa,
-	0x04ac,
-	0x04ae,
-	0x04b0,
-	0x04b2,
-	0x04b4,
-	0x04b6,
-	0x04b8,
-	0x04ba,
-	0x04bc,
-	0x04be,
-	0x04c3,
-	0x04c5,
-	0x04c7,
-	0x04c9,
-	0x04cb,
-	0x04cd,
-	0x04d0,
-	0x04d2,
-	0x04d4,
-	0x04d6,
-	0x04d8,
-	0x04da,
-	0x04dc,
-	0x04de,
-	0x04e0,
-	0x04e2,
-	0x04e4,
-	0x04e6,
-	0x04e8,
-	0x04ea,
-	0x04ec,
-	0x04ee,
-	0x04f0,
-	0x04f2,
-	0x04f4,
-	0x04f6,
-	0x04f8,
-	0x04fa,
-	0x04fc,
-	0x04fe,
-	0x0500,
-	0x0502,
-	0x0504,
-	0x0506,
-	0x0508,
-	0x050a,
-	0x050c,
-	0x050e,
-	0x0510,
-	0x0512,
-	0x0514,
-	0x0516,
-	0x0518,
-	0x051a,
-	0x051c,
-	0x051e,
-	0x0520,
-	0x0522,
-	0x0524,
-	0x0526,
-	0x10c7,
-	0x10cd,
-	0x1e00,
-	0x1e02,
-	0x1e04,
-	0x1e06,
-	0x1e08,
-	0x1e0a,
-	0x1e0c,
-	0x1e0e,
-	0x1e10,
-	0x1e12,
-	0x1e14,
-	0x1e16,
-	0x1e18,
-	0x1e1a,
-	0x1e1c,
-	0x1e1e,
-	0x1e20,
-	0x1e22,
-	0x1e24,
-	0x1e26,
-	0x1e28,
-	0x1e2a,
-	0x1e2c,
-	0x1e2e,
-	0x1e30,
-	0x1e32,
-	0x1e34,
-	0x1e36,
-	0x1e38,
-	0x1e3a,
-	0x1e3c,
-	0x1e3e,
-	0x1e40,
-	0x1e42,
-	0x1e44,
-	0x1e46,
-	0x1e48,
-	0x1e4a,
-	0x1e4c,
-	0x1e4e,
-	0x1e50,
-	0x1e52,
-	0x1e54,
-	0x1e56,
-	0x1e58,
-	0x1e5a,
-	0x1e5c,
-	0x1e5e,
-	0x1e60,
-	0x1e62,
-	0x1e64,
-	0x1e66,
-	0x1e68,
-	0x1e6a,
-	0x1e6c,
-	0x1e6e,
-	0x1e70,
-	0x1e72,
-	0x1e74,
-	0x1e76,
-	0x1e78,
-	0x1e7a,
-	0x1e7c,
-	0x1e7e,
-	0x1e80,
-	0x1e82,
-	0x1e84,
-	0x1e86,
-	0x1e88,
-	0x1e8a,
-	0x1e8c,
-	0x1e8e,
-	0x1e90,
-	0x1e92,
-	0x1e94,
-	0x1e9e,
-	0x1ea0,
-	0x1ea2,
-	0x1ea4,
-	0x1ea6,
-	0x1ea8,
-	0x1eaa,
-	0x1eac,
-	0x1eae,
-	0x1eb0,
-	0x1eb2,
-	0x1eb4,
-	0x1eb6,
-	0x1eb8,
-	0x1eba,
-	0x1ebc,
-	0x1ebe,
-	0x1ec0,
-	0x1ec2,
-	0x1ec4,
-	0x1ec6,
-	0x1ec8,
-	0x1eca,
-	0x1ecc,
-	0x1ece,
-	0x1ed0,
-	0x1ed2,
-	0x1ed4,
-	0x1ed6,
-	0x1ed8,
-	0x1eda,
-	0x1edc,
-	0x1ede,
-	0x1ee0,
-	0x1ee2,
-	0x1ee4,
-	0x1ee6,
-	0x1ee8,
-	0x1eea,
-	0x1eec,
-	0x1eee,
-	0x1ef0,
-	0x1ef2,
-	0x1ef4,
-	0x1ef6,
-	0x1ef8,
-	0x1efa,
-	0x1efc,
-	0x1efe,
-	0x1f59,
-	0x1f5b,
-	0x1f5d,
-	0x1f5f,
-	0x2102,
-	0x2107,
-	0x2115,
-	0x2124,
-	0x2126,
-	0x2128,
-	0x2145,
-	0x2183,
-	0x2c60,
-	0x2c67,
-	0x2c69,
-	0x2c6b,
-	0x2c72,
-	0x2c75,
-	0x2c82,
-	0x2c84,
-	0x2c86,
-	0x2c88,
-	0x2c8a,
-	0x2c8c,
-	0x2c8e,
-	0x2c90,
-	0x2c92,
-	0x2c94,
-	0x2c96,
-	0x2c98,
-	0x2c9a,
-	0x2c9c,
-	0x2c9e,
-	0x2ca0,
-	0x2ca2,
-	0x2ca4,
-	0x2ca6,
-	0x2ca8,
-	0x2caa,
-	0x2cac,
-	0x2cae,
-	0x2cb0,
-	0x2cb2,
-	0x2cb4,
-	0x2cb6,
-	0x2cb8,
-	0x2cba,
-	0x2cbc,
-	0x2cbe,
-	0x2cc0,
-	0x2cc2,
-	0x2cc4,
-	0x2cc6,
-	0x2cc8,
-	0x2cca,
-	0x2ccc,
-	0x2cce,
-	0x2cd0,
-	0x2cd2,
-	0x2cd4,
-	0x2cd6,
-	0x2cd8,
-	0x2cda,
-	0x2cdc,
-	0x2cde,
-	0x2ce0,
-	0x2ce2,
-	0x2ceb,
-	0x2ced,
-	0x2cf2,
-	0xa640,
-	0xa642,
-	0xa644,
-	0xa646,
-	0xa648,
-	0xa64a,
-	0xa64c,
-	0xa64e,
-	0xa650,
-	0xa652,
-	0xa654,
-	0xa656,
-	0xa658,
-	0xa65a,
-	0xa65c,
-	0xa65e,
-	0xa660,
-	0xa662,
-	0xa664,
-	0xa666,
-	0xa668,
-	0xa66a,
-	0xa66c,
-	0xa680,
-	0xa682,
-	0xa684,
-	0xa686,
-	0xa688,
-	0xa68a,
-	0xa68c,
-	0xa68e,
-	0xa690,
-	0xa692,
-	0xa694,
-	0xa696,
-	0xa722,
-	0xa724,
-	0xa726,
-	0xa728,
-	0xa72a,
-	0xa72c,
-	0xa72e,
-	0xa732,
-	0xa734,
-	0xa736,
-	0xa738,
-	0xa73a,
-	0xa73c,
-	0xa73e,
-	0xa740,
-	0xa742,
-	0xa744,
-	0xa746,
-	0xa748,
-	0xa74a,
-	0xa74c,
-	0xa74e,
-	0xa750,
-	0xa752,
-	0xa754,
-	0xa756,
-	0xa758,
-	0xa75a,
-	0xa75c,
-	0xa75e,
-	0xa760,
-	0xa762,
-	0xa764,
-	0xa766,
-	0xa768,
-	0xa76a,
-	0xa76c,
-	0xa76e,
-	0xa779,
-	0xa77b,
-	0xa780,
-	0xa782,
-	0xa784,
-	0xa786,
-	0xa78b,
-	0xa78d,
-	0xa790,
-	0xa792,
-	0xa7a0,
-	0xa7a2,
-	0xa7a4,
-	0xa7a6,
-	0xa7a8,
-	0xa7aa,
-	0x1d49c,
-	0x1d4a2,
-	0x1d546,
-	0x1d7ca,
-};
-
-/* }}} */
-
-/* {{{ Unicode lower */
-
-static uint32_t islowerr[] = {
-	0x0061, 0x007a,
-	0x00df, 0x00f6,
-	0x00f8, 0x00ff,
-	0x0137, 0x0138,
-	0x0148, 0x0149,
-	0x017e, 0x0180,
-	0x018c, 0x018d,
-	0x0199, 0x019b,
-	0x01aa, 0x01ab,
-	0x01b9, 0x01ba,
-	0x01bd, 0x01bf,
-	0x01dc, 0x01dd,
-	0x01ef, 0x01f0,
-	0x0233, 0x0239,
-	0x023f, 0x0240,
-	0x024f, 0x0293,
-	0x0295, 0x02af,
-	0x037b, 0x037d,
-	0x03ac, 0x03ce,
-	0x03d0, 0x03d1,
-	0x03d5, 0x03d7,
-	0x03ef, 0x03f3,
-	0x03fb, 0x03fc,
-	0x0430, 0x045f,
-	0x04ce, 0x04cf,
-	0x0561, 0x0587,
-	0x1d00, 0x1d2b,
-	0x1d6b, 0x1d77,
-	0x1d79, 0x1d9a,
-	0x1e95, 0x1e9d,
-	0x1eff, 0x1f07,
-	0x1f10, 0x1f15,
-	0x1f20, 0x1f27,
-	0x1f30, 0x1f37,
-	0x1f40, 0x1f45,
-	0x1f50, 0x1f57,
-	0x1f60, 0x1f67,
-	0x1f70, 0x1f7d,
-	0x1f80, 0x1f87,
-	0x1f90, 0x1f97,
-	0x1fa0, 0x1fa7,
-	0x1fb0, 0x1fb4,
-	0x1fb6, 0x1fb7,
-	0x1fc2, 0x1fc4,
-	0x1fc6, 0x1fc7,
-	0x1fd0, 0x1fd3,
-	0x1fd6, 0x1fd7,
-	0x1fe0, 0x1fe7,
-	0x1ff2, 0x1ff4,
-	0x1ff6, 0x1ff7,
-	0x210e, 0x210f,
-	0x213c, 0x213d,
-	0x2146, 0x2149,
-	0x2170, 0x217f,
-	0x24d0, 0x24e9,
-	0x2c30, 0x2c5e,
-	0x2c65, 0x2c66,
-	0x2c73, 0x2c74,
-	0x2c76, 0x2c7b,
-	0x2ce3, 0x2ce4,
-	0x2d00, 0x2d25,
-	0xa72f, 0xa731,
-	0xa771, 0xa778,
-	0xfb00, 0xfb06,
-	0xfb13, 0xfb17,
-	0xff41, 0xff5a,
-	0x10428, 0x1044f,
-	0x1d41a, 0x1d433,
-	0x1d44e, 0x1d454,
-	0x1d456, 0x1d467,
-	0x1d482, 0x1d49b,
-	0x1d4b6, 0x1d4b9,
-	0x1d4bd, 0x1d4c3,
-	0x1d4c5, 0x1d4cf,
-	0x1d4ea, 0x1d503,
-	0x1d51e, 0x1d537,
-	0x1d552, 0x1d56b,
-	0x1d586, 0x1d59f,
-	0x1d5ba, 0x1d5d3,
-	0x1d5ee, 0x1d607,
-	0x1d622, 0x1d63b,
-	0x1d656, 0x1d66f,
-	0x1d68a, 0x1d6a5,
-	0x1d6c2, 0x1d6da,
-	0x1d6dc, 0x1d6e1,
-	0x1d6fc, 0x1d714,
-	0x1d716, 0x1d71b,
-	0x1d736, 0x1d74e,
-	0x1d750, 0x1d755,
-	0x1d770, 0x1d788,
-	0x1d78a, 0x1d78f,
-	0x1d7aa, 0x1d7c2,
-	0x1d7c4, 0x1d7c9,
-};
-
-/* }}} */
-
-/* {{{ Lower */
-
-static uint32_t islowers[] = {
-	0x00b5,
-	0x0101,
-	0x0103,
-	0x0105,
-	0x0107,
-	0x0109,
-	0x010b,
-	0x010d,
-	0x010f,
-	0x0111,
-	0x0113,
-	0x0115,
-	0x0117,
-	0x0119,
-	0x011b,
-	0x011d,
-	0x011f,
-	0x0121,
-	0x0123,
-	0x0125,
-	0x0127,
-	0x0129,
-	0x012b,
-	0x012d,
-	0x012f,
-	0x0131,
-	0x0133,
-	0x0135,
-	0x013a,
-	0x013c,
-	0x013e,
-	0x0140,
-	0x0142,
-	0x0144,
-	0x0146,
-	0x014b,
-	0x014d,
-	0x014f,
-	0x0151,
-	0x0153,
-	0x0155,
-	0x0157,
-	0x0159,
-	0x015b,
-	0x015d,
-	0x015f,
-	0x0161,
-	0x0163,
-	0x0165,
-	0x0167,
-	0x0169,
-	0x016b,
-	0x016d,
-	0x016f,
-	0x0171,
-	0x0173,
-	0x0175,
-	0x0177,
-	0x017a,
-	0x017c,
-	0x0183,
-	0x0185,
-	0x0188,
-	0x0192,
-	0x0195,
-	0x019e,
-	0x01a1,
-	0x01a3,
-	0x01a5,
-	0x01a8,
-	0x01ad,
-	0x01b0,
-	0x01b4,
-	0x01b6,
-	0x01c6,
-	0x01c9,
-	0x01cc,
-	0x01ce,
-	0x01d0,
-	0x01d2,
-	0x01d4,
-	0x01d6,
-	0x01d8,
-	0x01da,
-	0x01df,
-	0x01e1,
-	0x01e3,
-	0x01e5,
-	0x01e7,
-	0x01e9,
-	0x01eb,
-	0x01ed,
-	0x01f3,
-	0x01f5,
-	0x01f9,
-	0x01fb,
-	0x01fd,
-	0x01ff,
-	0x0201,
-	0x0203,
-	0x0205,
-	0x0207,
-	0x0209,
-	0x020b,
-	0x020d,
-	0x020f,
-	0x0211,
-	0x0213,
-	0x0215,
-	0x0217,
-	0x0219,
-	0x021b,
-	0x021d,
-	0x021f,
-	0x0221,
-	0x0223,
-	0x0225,
-	0x0227,
-	0x0229,
-	0x022b,
-	0x022d,
-	0x022f,
-	0x0231,
-	0x023c,
-	0x0242,
-	0x0247,
-	0x0249,
-	0x024b,
-	0x024d,
-	0x0371,
-	0x0373,
-	0x0377,
-	0x0390,
-	0x03d9,
-	0x03db,
-	0x03dd,
-	0x03df,
-	0x03e1,
-	0x03e3,
-	0x03e5,
-	0x03e7,
-	0x03e9,
-	0x03eb,
-	0x03ed,
-	0x03f5,
-	0x03f8,
-	0x0461,
-	0x0463,
-	0x0465,
-	0x0467,
-	0x0469,
-	0x046b,
-	0x046d,
-	0x046f,
-	0x0471,
-	0x0473,
-	0x0475,
-	0x0477,
-	0x0479,
-	0x047b,
-	0x047d,
-	0x047f,
-	0x0481,
-	0x048b,
-	0x048d,
-	0x048f,
-	0x0491,
-	0x0493,
-	0x0495,
-	0x0497,
-	0x0499,
-	0x049b,
-	0x049d,
-	0x049f,
-	0x04a1,
-	0x04a3,
-	0x04a5,
-	0x04a7,
-	0x04a9,
-	0x04ab,
-	0x04ad,
-	0x04af,
-	0x04b1,
-	0x04b3,
-	0x04b5,
-	0x04b7,
-	0x04b9,
-	0x04bb,
-	0x04bd,
-	0x04bf,
-	0x04c2,
-	0x04c4,
-	0x04c6,
-	0x04c8,
-	0x04ca,
-	0x04cc,
-	0x04d1,
-	0x04d3,
-	0x04d5,
-	0x04d7,
-	0x04d9,
-	0x04db,
-	0x04dd,
-	0x04df,
-	0x04e1,
-	0x04e3,
-	0x04e5,
-	0x04e7,
-	0x04e9,
-	0x04eb,
-	0x04ed,
-	0x04ef,
-	0x04f1,
-	0x04f3,
-	0x04f5,
-	0x04f7,
-	0x04f9,
-	0x04fb,
-	0x04fd,
-	0x04ff,
-	0x0501,
-	0x0503,
-	0x0505,
-	0x0507,
-	0x0509,
-	0x050b,
-	0x050d,
-	0x050f,
-	0x0511,
-	0x0513,
-	0x0515,
-	0x0517,
-	0x0519,
-	0x051b,
-	0x051d,
-	0x051f,
-	0x0521,
-	0x0523,
-	0x0525,
-	0x0527,
-	0x1e01,
-	0x1e03,
-	0x1e05,
-	0x1e07,
-	0x1e09,
-	0x1e0b,
-	0x1e0d,
-	0x1e0f,
-	0x1e11,
-	0x1e13,
-	0x1e15,
-	0x1e17,
-	0x1e19,
-	0x1e1b,
-	0x1e1d,
-	0x1e1f,
-	0x1e21,
-	0x1e23,
-	0x1e25,
-	0x1e27,
-	0x1e29,
-	0x1e2b,
-	0x1e2d,
-	0x1e2f,
-	0x1e31,
-	0x1e33,
-	0x1e35,
-	0x1e37,
-	0x1e39,
-	0x1e3b,
-	0x1e3d,
-	0x1e3f,
-	0x1e41,
-	0x1e43,
-	0x1e45,
-	0x1e47,
-	0x1e49,
-	0x1e4b,
-	0x1e4d,
-	0x1e4f,
-	0x1e51,
-	0x1e53,
-	0x1e55,
-	0x1e57,
-	0x1e59,
-	0x1e5b,
-	0x1e5d,
-	0x1e5f,
-	0x1e61,
-	0x1e63,
-	0x1e65,
-	0x1e67,
-	0x1e69,
-	0x1e6b,
-	0x1e6d,
-	0x1e6f,
-	0x1e71,
-	0x1e73,
-	0x1e75,
-	0x1e77,
-	0x1e79,
-	0x1e7b,
-	0x1e7d,
-	0x1e7f,
-	0x1e81,
-	0x1e83,
-	0x1e85,
-	0x1e87,
-	0x1e89,
-	0x1e8b,
-	0x1e8d,
-	0x1e8f,
-	0x1e91,
-	0x1e93,
-	0x1e9f,
-	0x1ea1,
-	0x1ea3,
-	0x1ea5,
-	0x1ea7,
-	0x1ea9,
-	0x1eab,
-	0x1ead,
-	0x1eaf,
-	0x1eb1,
-	0x1eb3,
-	0x1eb5,
-	0x1eb7,
-	0x1eb9,
-	0x1ebb,
-	0x1ebd,
-	0x1ebf,
-	0x1ec1,
-	0x1ec3,
-	0x1ec5,
-	0x1ec7,
-	0x1ec9,
-	0x1ecb,
-	0x1ecd,
-	0x1ecf,
-	0x1ed1,
-	0x1ed3,
-	0x1ed5,
-	0x1ed7,
-	0x1ed9,
-	0x1edb,
-	0x1edd,
-	0x1edf,
-	0x1ee1,
-	0x1ee3,
-	0x1ee5,
-	0x1ee7,
-	0x1ee9,
-	0x1eeb,
-	0x1eed,
-	0x1eef,
-	0x1ef1,
-	0x1ef3,
-	0x1ef5,
-	0x1ef7,
-	0x1ef9,
-	0x1efb,
-	0x1efd,
-	0x1fbe,
-	0x210a,
-	0x2113,
-	0x212f,
-	0x2134,
-	0x2139,
-	0x214e,
-	0x2184,
-	0x2c61,
-	0x2c68,
-	0x2c6a,
-	0x2c6c,
-	0x2c71,
-	0x2c81,
-	0x2c83,
-	0x2c85,
-	0x2c87,
-	0x2c89,
-	0x2c8b,
-	0x2c8d,
-	0x2c8f,
-	0x2c91,
-	0x2c93,
-	0x2c95,
-	0x2c97,
-	0x2c99,
-	0x2c9b,
-	0x2c9d,
-	0x2c9f,
-	0x2ca1,
-	0x2ca3,
-	0x2ca5,
-	0x2ca7,
-	0x2ca9,
-	0x2cab,
-	0x2cad,
-	0x2caf,
-	0x2cb1,
-	0x2cb3,
-	0x2cb5,
-	0x2cb7,
-	0x2cb9,
-	0x2cbb,
-	0x2cbd,
-	0x2cbf,
-	0x2cc1,
-	0x2cc3,
-	0x2cc5,
-	0x2cc7,
-	0x2cc9,
-	0x2ccb,
-	0x2ccd,
-	0x2ccf,
-	0x2cd1,
-	0x2cd3,
-	0x2cd5,
-	0x2cd7,
-	0x2cd9,
-	0x2cdb,
-	0x2cdd,
-	0x2cdf,
-	0x2ce1,
-	0x2cec,
-	0x2cee,
-	0x2cf3,
-	0x2d27,
-	0x2d2d,
-	0xa641,
-	0xa643,
-	0xa645,
-	0xa647,
-	0xa649,
-	0xa64b,
-	0xa64d,
-	0xa64f,
-	0xa651,
-	0xa653,
-	0xa655,
-	0xa657,
-	0xa659,
-	0xa65b,
-	0xa65d,
-	0xa65f,
-	0xa661,
-	0xa663,
-	0xa665,
-	0xa667,
-	0xa669,
-	0xa66b,
-	0xa66d,
-	0xa681,
-	0xa683,
-	0xa685,
-	0xa687,
-	0xa689,
-	0xa68b,
-	0xa68d,
-	0xa68f,
-	0xa691,
-	0xa693,
-	0xa695,
-	0xa697,
-	0xa723,
-	0xa725,
-	0xa727,
-	0xa729,
-	0xa72b,
-	0xa72d,
-	0xa733,
-	0xa735,
-	0xa737,
-	0xa739,
-	0xa73b,
-	0xa73d,
-	0xa73f,
-	0xa741,
-	0xa743,
-	0xa745,
-	0xa747,
-	0xa749,
-	0xa74b,
-	0xa74d,
-	0xa74f,
-	0xa751,
-	0xa753,
-	0xa755,
-	0xa757,
-	0xa759,
-	0xa75b,
-	0xa75d,
-	0xa75f,
-	0xa761,
-	0xa763,
-	0xa765,
-	0xa767,
-	0xa769,
-	0xa76b,
-	0xa76d,
-	0xa76f,
-	0xa77a,
-	0xa77c,
-	0xa77f,
-	0xa781,
-	0xa783,
-	0xa785,
-	0xa787,
-	0xa78c,
-	0xa78e,
-	0xa791,
-	0xa793,
-	0xa7a1,
-	0xa7a3,
-	0xa7a5,
-	0xa7a7,
-	0xa7a9,
-	0xa7fa,
-	0x1d4bb,
-	0x1d7cb,
-};
-
-/* }}} */
-
-/* {{{ Unicode title */
-
-static uint32_t istitler[] = {
-	0x0041, 0x005a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00de,
-	0x0178, 0x0179,
-	0x0181, 0x0182,
-	0x0186, 0x0187,
-	0x0189, 0x018b,
-	0x018e, 0x0191,
-	0x0193, 0x0194,
-	0x0196, 0x0198,
-	0x019c, 0x019d,
-	0x019f, 0x01a0,
-	0x01a6, 0x01a7,
-	0x01ae, 0x01af,
-	0x01b1, 0x01b3,
-	0x01b7, 0x01b8,
-	0x01f6, 0x01f8,
-	0x023a, 0x023b,
-	0x023d, 0x023e,
-	0x0243, 0x0246,
-	0x0388, 0x038a,
-	0x038e, 0x038f,
-	0x0391, 0x03a1,
-	0x03a3, 0x03ab,
-	0x03f9, 0x03fa,
-	0x03fd, 0x042f,
-	0x04c0, 0x04c1,
-	0x0531, 0x0556,
-	0x10a0, 0x10c5,
-	0x1f08, 0x1f0f,
-	0x1f18, 0x1f1d,
-	0x1f28, 0x1f2f,
-	0x1f38, 0x1f3f,
-	0x1f48, 0x1f4d,
-	0x1f68, 0x1f6f,
-	0x1f88, 0x1f8f,
-	0x1f98, 0x1f9f,
-	0x1fa8, 0x1faf,
-	0x1fb8, 0x1fbc,
-	0x1fc8, 0x1fcc,
-	0x1fd8, 0x1fdb,
-	0x1fe8, 0x1fec,
-	0x1ff8, 0x1ffc,
-	0x2160, 0x216f,
-	0x24b6, 0x24cf,
-	0x2c00, 0x2c2e,
-	0x2c62, 0x2c64,
-	0x2c6d, 0x2c70,
-	0x2c7e, 0x2c80,
-	0xa77d, 0xa77e,
-	0xff21, 0xff3a,
-	0x10400, 0x10427,
-};
-
-/* }}} */
-
-/* {{{ Title */
-
-static uint32_t istitles[] = {
-	0x0100,
-	0x0102,
-	0x0104,
-	0x0106,
-	0x0108,
-	0x010a,
-	0x010c,
-	0x010e,
-	0x0110,
-	0x0112,
-	0x0114,
-	0x0116,
-	0x0118,
-	0x011a,
-	0x011c,
-	0x011e,
-	0x0120,
-	0x0122,
-	0x0124,
-	0x0126,
-	0x0128,
-	0x012a,
-	0x012c,
-	0x012e,
-	0x0132,
-	0x0134,
-	0x0136,
-	0x0139,
-	0x013b,
-	0x013d,
-	0x013f,
-	0x0141,
-	0x0143,
-	0x0145,
-	0x0147,
-	0x014a,
-	0x014c,
-	0x014e,
-	0x0150,
-	0x0152,
-	0x0154,
-	0x0156,
-	0x0158,
-	0x015a,
-	0x015c,
-	0x015e,
-	0x0160,
-	0x0162,
-	0x0164,
-	0x0166,
-	0x0168,
-	0x016a,
-	0x016c,
-	0x016e,
-	0x0170,
-	0x0172,
-	0x0174,
-	0x0176,
-	0x017b,
-	0x017d,
-	0x0184,
-	0x01a2,
-	0x01a4,
-	0x01a9,
-	0x01ac,
-	0x01b5,
-	0x01bc,
-	0x01c5,
-	0x01c8,
-	0x01cb,
-	0x01cd,
-	0x01cf,
-	0x01d1,
-	0x01d3,
-	0x01d5,
-	0x01d7,
-	0x01d9,
-	0x01db,
-	0x01de,
-	0x01e0,
-	0x01e2,
-	0x01e4,
-	0x01e6,
-	0x01e8,
-	0x01ea,
-	0x01ec,
-	0x01ee,
-	0x01f2,
-	0x01f4,
-	0x01fa,
-	0x01fc,
-	0x01fe,
-	0x0200,
-	0x0202,
-	0x0204,
-	0x0206,
-	0x0208,
-	0x020a,
-	0x020c,
-	0x020e,
-	0x0210,
-	0x0212,
-	0x0214,
-	0x0216,
-	0x0218,
-	0x021a,
-	0x021c,
-	0x021e,
-	0x0220,
-	0x0222,
-	0x0224,
-	0x0226,
-	0x0228,
-	0x022a,
-	0x022c,
-	0x022e,
-	0x0230,
-	0x0232,
-	0x0241,
-	0x0248,
-	0x024a,
-	0x024c,
-	0x024e,
-	0x0370,
-	0x0372,
-	0x0376,
-	0x0386,
-	0x038c,
-	0x03cf,
-	0x03d8,
-	0x03da,
-	0x03dc,
-	0x03de,
-	0x03e0,
-	0x03e2,
-	0x03e4,
-	0x03e6,
-	0x03e8,
-	0x03ea,
-	0x03ec,
-	0x03ee,
-	0x03f7,
-	0x0460,
-	0x0462,
-	0x0464,
-	0x0466,
-	0x0468,
-	0x046a,
-	0x046c,
-	0x046e,
-	0x0470,
-	0x0472,
-	0x0474,
-	0x0476,
-	0x0478,
-	0x047a,
-	0x047c,
-	0x047e,
-	0x0480,
-	0x048a,
-	0x048c,
-	0x048e,
-	0x0490,
-	0x0492,
-	0x0494,
-	0x0496,
-	0x0498,
-	0x049a,
-	0x049c,
-	0x049e,
-	0x04a0,
-	0x04a2,
-	0x04a4,
-	0x04a6,
-	0x04a8,
-	0x04aa,
-	0x04ac,
-	0x04ae,
-	0x04b0,
-	0x04b2,
-	0x04b4,
-	0x04b6,
-	0x04b8,
-	0x04ba,
-	0x04bc,
-	0x04be,
-	0x04c3,
-	0x04c5,
-	0x04c7,
-	0x04c9,
-	0x04cb,
-	0x04cd,
-	0x04d0,
-	0x04d2,
-	0x04d4,
-	0x04d6,
-	0x04d8,
-	0x04da,
-	0x04dc,
-	0x04de,
-	0x04e0,
-	0x04e2,
-	0x04e4,
-	0x04e6,
-	0x04e8,
-	0x04ea,
-	0x04ec,
-	0x04ee,
-	0x04f0,
-	0x04f2,
-	0x04f4,
-	0x04f6,
-	0x04f8,
-	0x04fa,
-	0x04fc,
-	0x04fe,
-	0x0500,
-	0x0502,
-	0x0504,
-	0x0506,
-	0x0508,
-	0x050a,
-	0x050c,
-	0x050e,
-	0x0510,
-	0x0512,
-	0x0514,
-	0x0516,
-	0x0518,
-	0x051a,
-	0x051c,
-	0x051e,
-	0x0520,
-	0x0522,
-	0x0524,
-	0x0526,
-	0x10c7,
-	0x10cd,
-	0x1e00,
-	0x1e02,
-	0x1e04,
-	0x1e06,
-	0x1e08,
-	0x1e0a,
-	0x1e0c,
-	0x1e0e,
-	0x1e10,
-	0x1e12,
-	0x1e14,
-	0x1e16,
-	0x1e18,
-	0x1e1a,
-	0x1e1c,
-	0x1e1e,
-	0x1e20,
-	0x1e22,
-	0x1e24,
-	0x1e26,
-	0x1e28,
-	0x1e2a,
-	0x1e2c,
-	0x1e2e,
-	0x1e30,
-	0x1e32,
-	0x1e34,
-	0x1e36,
-	0x1e38,
-	0x1e3a,
-	0x1e3c,
-	0x1e3e,
-	0x1e40,
-	0x1e42,
-	0x1e44,
-	0x1e46,
-	0x1e48,
-	0x1e4a,
-	0x1e4c,
-	0x1e4e,
-	0x1e50,
-	0x1e52,
-	0x1e54,
-	0x1e56,
-	0x1e58,
-	0x1e5a,
-	0x1e5c,
-	0x1e5e,
-	0x1e60,
-	0x1e62,
-	0x1e64,
-	0x1e66,
-	0x1e68,
-	0x1e6a,
-	0x1e6c,
-	0x1e6e,
-	0x1e70,
-	0x1e72,
-	0x1e74,
-	0x1e76,
-	0x1e78,
-	0x1e7a,
-	0x1e7c,
-	0x1e7e,
-	0x1e80,
-	0x1e82,
-	0x1e84,
-	0x1e86,
-	0x1e88,
-	0x1e8a,
-	0x1e8c,
-	0x1e8e,
-	0x1e90,
-	0x1e92,
-	0x1e94,
-	0x1ea0,
-	0x1ea2,
-	0x1ea4,
-	0x1ea6,
-	0x1ea8,
-	0x1eaa,
-	0x1eac,
-	0x1eae,
-	0x1eb0,
-	0x1eb2,
-	0x1eb4,
-	0x1eb6,
-	0x1eb8,
-	0x1eba,
-	0x1ebc,
-	0x1ebe,
-	0x1ec0,
-	0x1ec2,
-	0x1ec4,
-	0x1ec6,
-	0x1ec8,
-	0x1eca,
-	0x1ecc,
-	0x1ece,
-	0x1ed0,
-	0x1ed2,
-	0x1ed4,
-	0x1ed6,
-	0x1ed8,
-	0x1eda,
-	0x1edc,
-	0x1ede,
-	0x1ee0,
-	0x1ee2,
-	0x1ee4,
-	0x1ee6,
-	0x1ee8,
-	0x1eea,
-	0x1eec,
-	0x1eee,
-	0x1ef0,
-	0x1ef2,
-	0x1ef4,
-	0x1ef6,
-	0x1ef8,
-	0x1efa,
-	0x1efc,
-	0x1efe,
-	0x1f59,
-	0x1f5b,
-	0x1f5d,
-	0x1f5f,
-	0x2132,
-	0x2183,
-	0x2c60,
-	0x2c67,
-	0x2c69,
-	0x2c6b,
-	0x2c72,
-	0x2c75,
-	0x2c82,
-	0x2c84,
-	0x2c86,
-	0x2c88,
-	0x2c8a,
-	0x2c8c,
-	0x2c8e,
-	0x2c90,
-	0x2c92,
-	0x2c94,
-	0x2c96,
-	0x2c98,
-	0x2c9a,
-	0x2c9c,
-	0x2c9e,
-	0x2ca0,
-	0x2ca2,
-	0x2ca4,
-	0x2ca6,
-	0x2ca8,
-	0x2caa,
-	0x2cac,
-	0x2cae,
-	0x2cb0,
-	0x2cb2,
-	0x2cb4,
-	0x2cb6,
-	0x2cb8,
-	0x2cba,
-	0x2cbc,
-	0x2cbe,
-	0x2cc0,
-	0x2cc2,
-	0x2cc4,
-	0x2cc6,
-	0x2cc8,
-	0x2cca,
-	0x2ccc,
-	0x2cce,
-	0x2cd0,
-	0x2cd2,
-	0x2cd4,
-	0x2cd6,
-	0x2cd8,
-	0x2cda,
-	0x2cdc,
-	0x2cde,
-	0x2ce0,
-	0x2ce2,
-	0x2ceb,
-	0x2ced,
-	0x2cf2,
-	0xa640,
-	0xa642,
-	0xa644,
-	0xa646,
-	0xa648,
-	0xa64a,
-	0xa64c,
-	0xa64e,
-	0xa650,
-	0xa652,
-	0xa654,
-	0xa656,
-	0xa658,
-	0xa65a,
-	0xa65c,
-	0xa65e,
-	0xa660,
-	0xa662,
-	0xa664,
-	0xa666,
-	0xa668,
-	0xa66a,
-	0xa66c,
-	0xa680,
-	0xa682,
-	0xa684,
-	0xa686,
-	0xa688,
-	0xa68a,
-	0xa68c,
-	0xa68e,
-	0xa690,
-	0xa692,
-	0xa694,
-	0xa696,
-	0xa722,
-	0xa724,
-	0xa726,
-	0xa728,
-	0xa72a,
-	0xa72c,
-	0xa72e,
-	0xa732,
-	0xa734,
-	0xa736,
-	0xa738,
-	0xa73a,
-	0xa73c,
-	0xa73e,
-	0xa740,
-	0xa742,
-	0xa744,
-	0xa746,
-	0xa748,
-	0xa74a,
-	0xa74c,
-	0xa74e,
-	0xa750,
-	0xa752,
-	0xa754,
-	0xa756,
-	0xa758,
-	0xa75a,
-	0xa75c,
-	0xa75e,
-	0xa760,
-	0xa762,
-	0xa764,
-	0xa766,
-	0xa768,
-	0xa76a,
-	0xa76c,
-	0xa76e,
-	0xa779,
-	0xa77b,
-	0xa780,
-	0xa782,
-	0xa784,
-	0xa786,
-	0xa78b,
-	0xa78d,
-	0xa790,
-	0xa792,
-	0xa7a0,
-	0xa7a2,
-	0xa7a4,
-	0xa7a6,
-	0xa7a8,
-	0xa7aa,
-};
-
-/* }}} */
-
-/* {{{ To upper */
-
-static uint32_t toupperr[] = {
-	0x0061, 0x007a, 1048544,
-	0x00e0, 0x00f6, 1048544,
-	0x00f8, 0x00fe, 1048544,
-	0x023f, 0x0240, 1059391,
-	0x0256, 0x0257, 1048371,
-	0x028a, 0x028b, 1048359,
-	0x037b, 0x037d, 1048706,
-	0x03ad, 0x03af, 1048539,
-	0x03b1, 0x03c1, 1048544,
-	0x03c3, 0x03cb, 1048544,
-	0x03cd, 0x03ce, 1048513,
-	0x0430, 0x044f, 1048544,
-	0x0450, 0x045f, 1048496,
-	0x0561, 0x0586, 1048528,
-	0x1f00, 0x1f07, 1048584,
-	0x1f10, 0x1f15, 1048584,
-	0x1f20, 0x1f27, 1048584,
-	0x1f30, 0x1f37, 1048584,
-	0x1f40, 0x1f45, 1048584,
-	0x1f60, 0x1f67, 1048584,
-	0x1f70, 0x1f71, 1048650,
-	0x1f72, 0x1f75, 1048662,
-	0x1f76, 0x1f77, 1048676,
-	0x1f78, 0x1f79, 1048704,
-	0x1f7a, 0x1f7b, 1048688,
-	0x1f7c, 0x1f7d, 1048702,
-	0x1f80, 0x1f87, 1048584,
-	0x1f90, 0x1f97, 1048584,
-	0x1fa0, 0x1fa7, 1048584,
-	0x1fb0, 0x1fb1, 1048584,
-	0x1fd0, 0x1fd1, 1048584,
-	0x1fe0, 0x1fe1, 1048584,
-	0x2170, 0x217f, 1048560,
-	0x24d0, 0x24e9, 1048550,
-	0x2c30, 0x2c5e, 1048528,
-	0x2d00, 0x2d25, 1041312,
-	0xff41, 0xff5a, 1048544,
-	0x10428, 0x1044f, 1048536,
-};
-
-static uint32_t touppers[] = {
-	0x00b5, 1049319,
-	0x00ff, 1048697,
-	0x0101, 1048575,
-	0x0103, 1048575,
-	0x0105, 1048575,
-	0x0107, 1048575,
-	0x0109, 1048575,
-	0x010b, 1048575,
-	0x010d, 1048575,
-	0x010f, 1048575,
-	0x0111, 1048575,
-	0x0113, 1048575,
-	0x0115, 1048575,
-	0x0117, 1048575,
-	0x0119, 1048575,
-	0x011b, 1048575,
-	0x011d, 1048575,
-	0x011f, 1048575,
-	0x0121, 1048575,
-	0x0123, 1048575,
-	0x0125, 1048575,
-	0x0127, 1048575,
-	0x0129, 1048575,
-	0x012b, 1048575,
-	0x012d, 1048575,
-	0x012f, 1048575,
-	0x0131, 1048344,
-	0x0133, 1048575,
-	0x0135, 1048575,
-	0x0137, 1048575,
-	0x013a, 1048575,
-	0x013c, 1048575,
-	0x013e, 1048575,
-	0x0140, 1048575,
-	0x0142, 1048575,
-	0x0144, 1048575,
-	0x0146, 1048575,
-	0x0148, 1048575,
-	0x014b, 1048575,
-	0x014d, 1048575,
-	0x014f, 1048575,
-	0x0151, 1048575,
-	0x0153, 1048575,
-	0x0155, 1048575,
-	0x0157, 1048575,
-	0x0159, 1048575,
-	0x015b, 1048575,
-	0x015d, 1048575,
-	0x015f, 1048575,
-	0x0161, 1048575,
-	0x0163, 1048575,
-	0x0165, 1048575,
-	0x0167, 1048575,
-	0x0169, 1048575,
-	0x016b, 1048575,
-	0x016d, 1048575,
-	0x016f, 1048575,
-	0x0171, 1048575,
-	0x0173, 1048575,
-	0x0175, 1048575,
-	0x0177, 1048575,
-	0x017a, 1048575,
-	0x017c, 1048575,
-	0x017e, 1048575,
-	0x017f, 1048276,
-	0x0180, 1048771,
-	0x0183, 1048575,
-	0x0185, 1048575,
-	0x0188, 1048575,
-	0x018c, 1048575,
-	0x0192, 1048575,
-	0x0195, 1048673,
-	0x0199, 1048575,
-	0x019a, 1048739,
-	0x019e, 1048706,
-	0x01a1, 1048575,
-	0x01a3, 1048575,
-	0x01a5, 1048575,
-	0x01a8, 1048575,
-	0x01ad, 1048575,
-	0x01b0, 1048575,
-	0x01b4, 1048575,
-	0x01b6, 1048575,
-	0x01b9, 1048575,
-	0x01bd, 1048575,
-	0x01bf, 1048632,
-	0x01c5, 1048575,
-	0x01c6, 1048574,
-	0x01c8, 1048575,
-	0x01c9, 1048574,
-	0x01cb, 1048575,
-	0x01cc, 1048574,
-	0x01ce, 1048575,
-	0x01d0, 1048575,
-	0x01d2, 1048575,
-	0x01d4, 1048575,
-	0x01d6, 1048575,
-	0x01d8, 1048575,
-	0x01da, 1048575,
-	0x01dc, 1048575,
-	0x01dd, 1048497,
-	0x01df, 1048575,
-	0x01e1, 1048575,
-	0x01e3, 1048575,
-	0x01e5, 1048575,
-	0x01e7, 1048575,
-	0x01e9, 1048575,
-	0x01eb, 1048575,
-	0x01ed, 1048575,
-	0x01ef, 1048575,
-	0x01f2, 1048575,
-	0x01f3, 1048574,
-	0x01f5, 1048575,
-	0x01f9, 1048575,
-	0x01fb, 1048575,
-	0x01fd, 1048575,
-	0x01ff, 1048575,
-	0x0201, 1048575,
-	0x0203, 1048575,
-	0x0205, 1048575,
-	0x0207, 1048575,
-	0x0209, 1048575,
-	0x020b, 1048575,
-	0x020d, 1048575,
-	0x020f, 1048575,
-	0x0211, 1048575,
-	0x0213, 1048575,
-	0x0215, 1048575,
-	0x0217, 1048575,
-	0x0219, 1048575,
-	0x021b, 1048575,
-	0x021d, 1048575,
-	0x021f, 1048575,
-	0x0223, 1048575,
-	0x0225, 1048575,
-	0x0227, 1048575,
-	0x0229, 1048575,
-	0x022b, 1048575,
-	0x022d, 1048575,
-	0x022f, 1048575,
-	0x0231, 1048575,
-	0x0233, 1048575,
-	0x023c, 1048575,
-	0x0242, 1048575,
-	0x0247, 1048575,
-	0x0249, 1048575,
-	0x024b, 1048575,
-	0x024d, 1048575,
-	0x024f, 1048575,
-	0x0250, 1059359,
-	0x0251, 1059356,
-	0x0252, 1059358,
-	0x0253, 1048366,
-	0x0254, 1048370,
-	0x0259, 1048374,
-	0x025b, 1048373,
-	0x0260, 1048371,
-	0x0263, 1048369,
-	0x0265, 1090856,
-	0x0266, 1090884,
-	0x0268, 1048367,
-	0x0269, 1048365,
-	0x026b, 1059319,
-	0x026f, 1048365,
-	0x0271, 1059325,
-	0x0272, 1048363,
-	0x0275, 1048362,
-	0x027d, 1059303,
-	0x0280, 1048358,
-	0x0283, 1048358,
-	0x0288, 1048358,
-	0x0289, 1048507,
-	0x028c, 1048505,
-	0x0292, 1048357,
-	0x0345, 1048660,
-	0x0371, 1048575,
-	0x0373, 1048575,
-	0x0377, 1048575,
-	0x03ac, 1048538,
-	0x03c2, 1048545,
-	0x03cc, 1048512,
-	0x03d0, 1048514,
-	0x03d1, 1048519,
-	0x03d5, 1048529,
-	0x03d6, 1048522,
-	0x03d7, 1048568,
-	0x03d9, 1048575,
-	0x03db, 1048575,
-	0x03dd, 1048575,
-	0x03df, 1048575,
-	0x03e1, 1048575,
-	0x03e3, 1048575,
-	0x03e5, 1048575,
-	0x03e7, 1048575,
-	0x03e9, 1048575,
-	0x03eb, 1048575,
-	0x03ed, 1048575,
-	0x03ef, 1048575,
-	0x03f0, 1048490,
-	0x03f1, 1048496,
-	0x03f2, 1048583,
-	0x03f5, 1048480,
-	0x03f8, 1048575,
-	0x03fb, 1048575,
-	0x0461, 1048575,
-	0x0463, 1048575,
-	0x0465, 1048575,
-	0x0467, 1048575,
-	0x0469, 1048575,
-	0x046b, 1048575,
-	0x046d, 1048575,
-	0x046f, 1048575,
-	0x0471, 1048575,
-	0x0473, 1048575,
-	0x0475, 1048575,
-	0x0477, 1048575,
-	0x0479, 1048575,
-	0x047b, 1048575,
-	0x047d, 1048575,
-	0x047f, 1048575,
-	0x0481, 1048575,
-	0x048b, 1048575,
-	0x048d, 1048575,
-	0x048f, 1048575,
-	0x0491, 1048575,
-	0x0493, 1048575,
-	0x0495, 1048575,
-	0x0497, 1048575,
-	0x0499, 1048575,
-	0x049b, 1048575,
-	0x049d, 1048575,
-	0x049f, 1048575,
-	0x04a1, 1048575,
-	0x04a3, 1048575,
-	0x04a5, 1048575,
-	0x04a7, 1048575,
-	0x04a9, 1048575,
-	0x04ab, 1048575,
-	0x04ad, 1048575,
-	0x04af, 1048575,
-	0x04b1, 1048575,
-	0x04b3, 1048575,
-	0x04b5, 1048575,
-	0x04b7, 1048575,
-	0x04b9, 1048575,
-	0x04bb, 1048575,
-	0x04bd, 1048575,
-	0x04bf, 1048575,
-	0x04c2, 1048575,
-	0x04c4, 1048575,
-	0x04c6, 1048575,
-	0x04c8, 1048575,
-	0x04ca, 1048575,
-	0x04cc, 1048575,
-	0x04ce, 1048575,
-	0x04cf, 1048561,
-	0x04d1, 1048575,
-	0x04d3, 1048575,
-	0x04d5, 1048575,
-	0x04d7, 1048575,
-	0x04d9, 1048575,
-	0x04db, 1048575,
-	0x04dd, 1048575,
-	0x04df, 1048575,
-	0x04e1, 1048575,
-	0x04e3, 1048575,
-	0x04e5, 1048575,
-	0x04e7, 1048575,
-	0x04e9, 1048575,
-	0x04eb, 1048575,
-	0x04ed, 1048575,
-	0x04ef, 1048575,
-	0x04f1, 1048575,
-	0x04f3, 1048575,
-	0x04f5, 1048575,
-	0x04f7, 1048575,
-	0x04f9, 1048575,
-	0x04fb, 1048575,
-	0x04fd, 1048575,
-	0x04ff, 1048575,
-	0x0501, 1048575,
-	0x0503, 1048575,
-	0x0505, 1048575,
-	0x0507, 1048575,
-	0x0509, 1048575,
-	0x050b, 1048575,
-	0x050d, 1048575,
-	0x050f, 1048575,
-	0x0511, 1048575,
-	0x0513, 1048575,
-	0x0515, 1048575,
-	0x0517, 1048575,
-	0x0519, 1048575,
-	0x051b, 1048575,
-	0x051d, 1048575,
-	0x051f, 1048575,
-	0x0521, 1048575,
-	0x0523, 1048575,
-	0x0525, 1048575,
-	0x0527, 1048575,
-	0x1d79, 1083908,
-	0x1d7d, 1052390,
-	0x1e01, 1048575,
-	0x1e03, 1048575,
-	0x1e05, 1048575,
-	0x1e07, 1048575,
-	0x1e09, 1048575,
-	0x1e0b, 1048575,
-	0x1e0d, 1048575,
-	0x1e0f, 1048575,
-	0x1e11, 1048575,
-	0x1e13, 1048575,
-	0x1e15, 1048575,
-	0x1e17, 1048575,
-	0x1e19, 1048575,
-	0x1e1b, 1048575,
-	0x1e1d, 1048575,
-	0x1e1f, 1048575,
-	0x1e21, 1048575,
-	0x1e23, 1048575,
-	0x1e25, 1048575,
-	0x1e27, 1048575,
-	0x1e29, 1048575,
-	0x1e2b, 1048575,
-	0x1e2d, 1048575,
-	0x1e2f, 1048575,
-	0x1e31, 1048575,
-	0x1e33, 1048575,
-	0x1e35, 1048575,
-	0x1e37, 1048575,
-	0x1e39, 1048575,
-	0x1e3b, 1048575,
-	0x1e3d, 1048575,
-	0x1e3f, 1048575,
-	0x1e41, 1048575,
-	0x1e43, 1048575,
-	0x1e45, 1048575,
-	0x1e47, 1048575,
-	0x1e49, 1048575,
-	0x1e4b, 1048575,
-	0x1e4d, 1048575,
-	0x1e4f, 1048575,
-	0x1e51, 1048575,
-	0x1e53, 1048575,
-	0x1e55, 1048575,
-	0x1e57, 1048575,
-	0x1e59, 1048575,
-	0x1e5b, 1048575,
-	0x1e5d, 1048575,
-	0x1e5f, 1048575,
-	0x1e61, 1048575,
-	0x1e63, 1048575,
-	0x1e65, 1048575,
-	0x1e67, 1048575,
-	0x1e69, 1048575,
-	0x1e6b, 1048575,
-	0x1e6d, 1048575,
-	0x1e6f, 1048575,
-	0x1e71, 1048575,
-	0x1e73, 1048575,
-	0x1e75, 1048575,
-	0x1e77, 1048575,
-	0x1e79, 1048575,
-	0x1e7b, 1048575,
-	0x1e7d, 1048575,
-	0x1e7f, 1048575,
-	0x1e81, 1048575,
-	0x1e83, 1048575,
-	0x1e85, 1048575,
-	0x1e87, 1048575,
-	0x1e89, 1048575,
-	0x1e8b, 1048575,
-	0x1e8d, 1048575,
-	0x1e8f, 1048575,
-	0x1e91, 1048575,
-	0x1e93, 1048575,
-	0x1e95, 1048575,
-	0x1e9b, 1048517,
-	0x1ea1, 1048575,
-	0x1ea3, 1048575,
-	0x1ea5, 1048575,
-	0x1ea7, 1048575,
-	0x1ea9, 1048575,
-	0x1eab, 1048575,
-	0x1ead, 1048575,
-	0x1eaf, 1048575,
-	0x1eb1, 1048575,
-	0x1eb3, 1048575,
-	0x1eb5, 1048575,
-	0x1eb7, 1048575,
-	0x1eb9, 1048575,
-	0x1ebb, 1048575,
-	0x1ebd, 1048575,
-	0x1ebf, 1048575,
-	0x1ec1, 1048575,
-	0x1ec3, 1048575,
-	0x1ec5, 1048575,
-	0x1ec7, 1048575,
-	0x1ec9, 1048575,
-	0x1ecb, 1048575,
-	0x1ecd, 1048575,
-	0x1ecf, 1048575,
-	0x1ed1, 1048575,
-	0x1ed3, 1048575,
-	0x1ed5, 1048575,
-	0x1ed7, 1048575,
-	0x1ed9, 1048575,
-	0x1edb, 1048575,
-	0x1edd, 1048575,
-	0x1edf, 1048575,
-	0x1ee1, 1048575,
-	0x1ee3, 1048575,
-	0x1ee5, 1048575,
-	0x1ee7, 1048575,
-	0x1ee9, 1048575,
-	0x1eeb, 1048575,
-	0x1eed, 1048575,
-	0x1eef, 1048575,
-	0x1ef1, 1048575,
-	0x1ef3, 1048575,
-	0x1ef5, 1048575,
-	0x1ef7, 1048575,
-	0x1ef9, 1048575,
-	0x1efb, 1048575,
-	0x1efd, 1048575,
-	0x1eff, 1048575,
-	0x1f51, 1048584,
-	0x1f53, 1048584,
-	0x1f55, 1048584,
-	0x1f57, 1048584,
-	0x1fb3, 1048585,
-	0x1fbe, 1041371,
-	0x1fc3, 1048585,
-	0x1fe5, 1048583,
-	0x1ff3, 1048585,
-	0x214e, 1048548,
-	0x2184, 1048575,
-	0x2c61, 1048575,
-	0x2c65, 1037781,
-	0x2c66, 1037784,
-	0x2c68, 1048575,
-	0x2c6a, 1048575,
-	0x2c6c, 1048575,
-	0x2c73, 1048575,
-	0x2c76, 1048575,
-	0x2c81, 1048575,
-	0x2c83, 1048575,
-	0x2c85, 1048575,
-	0x2c87, 1048575,
-	0x2c89, 1048575,
-	0x2c8b, 1048575,
-	0x2c8d, 1048575,
-	0x2c8f, 1048575,
-	0x2c91, 1048575,
-	0x2c93, 1048575,
-	0x2c95, 1048575,
-	0x2c97, 1048575,
-	0x2c99, 1048575,
-	0x2c9b, 1048575,
-	0x2c9d, 1048575,
-	0x2c9f, 1048575,
-	0x2ca1, 1048575,
-	0x2ca3, 1048575,
-	0x2ca5, 1048575,
-	0x2ca7, 1048575,
-	0x2ca9, 1048575,
-	0x2cab, 1048575,
-	0x2cad, 1048575,
-	0x2caf, 1048575,
-	0x2cb1, 1048575,
-	0x2cb3, 1048575,
-	0x2cb5, 1048575,
-	0x2cb7, 1048575,
-	0x2cb9, 1048575,
-	0x2cbb, 1048575,
-	0x2cbd, 1048575,
-	0x2cbf, 1048575,
-	0x2cc1, 1048575,
-	0x2cc3, 1048575,
-	0x2cc5, 1048575,
-	0x2cc7, 1048575,
-	0x2cc9, 1048575,
-	0x2ccb, 1048575,
-	0x2ccd, 1048575,
-	0x2ccf, 1048575,
-	0x2cd1, 1048575,
-	0x2cd3, 1048575,
-	0x2cd5, 1048575,
-	0x2cd7, 1048575,
-	0x2cd9, 1048575,
-	0x2cdb, 1048575,
-	0x2cdd, 1048575,
-	0x2cdf, 1048575,
-	0x2ce1, 1048575,
-	0x2ce3, 1048575,
-	0x2cec, 1048575,
-	0x2cee, 1048575,
-	0x2cf3, 1048575,
-	0x2d27, 1041312,
-	0x2d2d, 1041312,
-	0xa641, 1048575,
-	0xa643, 1048575,
-	0xa645, 1048575,
-	0xa647, 1048575,
-	0xa649, 1048575,
-	0xa64b, 1048575,
-	0xa64d, 1048575,
-	0xa64f, 1048575,
-	0xa651, 1048575,
-	0xa653, 1048575,
-	0xa655, 1048575,
-	0xa657, 1048575,
-	0xa659, 1048575,
-	0xa65b, 1048575,
-	0xa65d, 1048575,
-	0xa65f, 1048575,
-	0xa661, 1048575,
-	0xa663, 1048575,
-	0xa665, 1048575,
-	0xa667, 1048575,
-	0xa669, 1048575,
-	0xa66b, 1048575,
-	0xa66d, 1048575,
-	0xa681, 1048575,
-	0xa683, 1048575,
-	0xa685, 1048575,
-	0xa687, 1048575,
-	0xa689, 1048575,
-	0xa68b, 1048575,
-	0xa68d, 1048575,
-	0xa68f, 1048575,
-	0xa691, 1048575,
-	0xa693, 1048575,
-	0xa695, 1048575,
-	0xa697, 1048575,
-	0xa723, 1048575,
-	0xa725, 1048575,
-	0xa727, 1048575,
-	0xa729, 1048575,
-	0xa72b, 1048575,
-	0xa72d, 1048575,
-	0xa72f, 1048575,
-	0xa733, 1048575,
-	0xa735, 1048575,
-	0xa737, 1048575,
-	0xa739, 1048575,
-	0xa73b, 1048575,
-	0xa73d, 1048575,
-	0xa73f, 1048575,
-	0xa741, 1048575,
-	0xa743, 1048575,
-	0xa745, 1048575,
-	0xa747, 1048575,
-	0xa749, 1048575,
-	0xa74b, 1048575,
-	0xa74d, 1048575,
-	0xa74f, 1048575,
-	0xa751, 1048575,
-	0xa753, 1048575,
-	0xa755, 1048575,
-	0xa757, 1048575,
-	0xa759, 1048575,
-	0xa75b, 1048575,
-	0xa75d, 1048575,
-	0xa75f, 1048575,
-	0xa761, 1048575,
-	0xa763, 1048575,
-	0xa765, 1048575,
-	0xa767, 1048575,
-	0xa769, 1048575,
-	0xa76b, 1048575,
-	0xa76d, 1048575,
-	0xa76f, 1048575,
-	0xa77a, 1048575,
-	0xa77c, 1048575,
-	0xa77f, 1048575,
-	0xa781, 1048575,
-	0xa783, 1048575,
-	0xa785, 1048575,
-	0xa787, 1048575,
-	0xa78c, 1048575,
-	0xa791, 1048575,
-	0xa793, 1048575,
-	0xa7a1, 1048575,
-	0xa7a3, 1048575,
-	0xa7a5, 1048575,
-	0xa7a7, 1048575,
-	0xa7a9, 1048575,
-};
-
-/* }}} */
-
-/* {{{ To lower */
-
-static uint32_t tolowerr[] = {
-	0x0041, 0x005a, 1048608,
-	0x00c0, 0x00d6, 1048608,
-	0x00d8, 0x00de, 1048608,
-	0x0189, 0x018a, 1048781,
-	0x01b1, 0x01b2, 1048793,
-	0x0388, 0x038a, 1048613,
-	0x038e, 0x038f, 1048639,
-	0x0391, 0x03a1, 1048608,
-	0x03a3, 0x03ab, 1048608,
-	0x03fd, 0x03ff, 1048446,
-	0x0400, 0x040f, 1048656,
-	0x0410, 0x042f, 1048608,
-	0x0531, 0x0556, 1048624,
-	0x10a0, 0x10c5, 1055840,
-	0x1f08, 0x1f0f, 1048568,
-	0x1f18, 0x1f1d, 1048568,
-	0x1f28, 0x1f2f, 1048568,
-	0x1f38, 0x1f3f, 1048568,
-	0x1f48, 0x1f4d, 1048568,
-	0x1f68, 0x1f6f, 1048568,
-	0x1f88, 0x1f8f, 1048568,
-	0x1f98, 0x1f9f, 1048568,
-	0x1fa8, 0x1faf, 1048568,
-	0x1fb8, 0x1fb9, 1048568,
-	0x1fba, 0x1fbb, 1048502,
-	0x1fc8, 0x1fcb, 1048490,
-	0x1fd8, 0x1fd9, 1048568,
-	0x1fda, 0x1fdb, 1048476,
-	0x1fe8, 0x1fe9, 1048568,
-	0x1fea, 0x1feb, 1048464,
-	0x1ff8, 0x1ff9, 1048448,
-	0x1ffa, 0x1ffb, 1048450,
-	0x2160, 0x216f, 1048592,
-	0x24b6, 0x24cf, 1048602,
-	0x2c00, 0x2c2e, 1048624,
-	0x2c7e, 0x2c7f, 1037761,
-	0xff21, 0xff3a, 1048608,
-	0x10400, 0x10427, 1048616,
-};
-
-static uint32_t tolowers[] = {
-	0x0100, 1048577,
-	0x0102, 1048577,
-	0x0104, 1048577,
-	0x0106, 1048577,
-	0x0108, 1048577,
-	0x010a, 1048577,
-	0x010c, 1048577,
-	0x010e, 1048577,
-	0x0110, 1048577,
-	0x0112, 1048577,
-	0x0114, 1048577,
-	0x0116, 1048577,
-	0x0118, 1048577,
-	0x011a, 1048577,
-	0x011c, 1048577,
-	0x011e, 1048577,
-	0x0120, 1048577,
-	0x0122, 1048577,
-	0x0124, 1048577,
-	0x0126, 1048577,
-	0x0128, 1048577,
-	0x012a, 1048577,
-	0x012c, 1048577,
-	0x012e, 1048577,
-	0x0130, 1048377,
-	0x0132, 1048577,
-	0x0134, 1048577,
-	0x0136, 1048577,
-	0x0139, 1048577,
-	0x013b, 1048577,
-	0x013d, 1048577,
-	0x013f, 1048577,
-	0x0141, 1048577,
-	0x0143, 1048577,
-	0x0145, 1048577,
-	0x0147, 1048577,
-	0x014a, 1048577,
-	0x014c, 1048577,
-	0x014e, 1048577,
-	0x0150, 1048577,
-	0x0152, 1048577,
-	0x0154, 1048577,
-	0x0156, 1048577,
-	0x0158, 1048577,
-	0x015a, 1048577,
-	0x015c, 1048577,
-	0x015e, 1048577,
-	0x0160, 1048577,
-	0x0162, 1048577,
-	0x0164, 1048577,
-	0x0166, 1048577,
-	0x0168, 1048577,
-	0x016a, 1048577,
-	0x016c, 1048577,
-	0x016e, 1048577,
-	0x0170, 1048577,
-	0x0172, 1048577,
-	0x0174, 1048577,
-	0x0176, 1048577,
-	0x0178, 1048455,
-	0x0179, 1048577,
-	0x017b, 1048577,
-	0x017d, 1048577,
-	0x0181, 1048786,
-	0x0182, 1048577,
-	0x0184, 1048577,
-	0x0186, 1048782,
-	0x0187, 1048577,
-	0x018b, 1048577,
-	0x018e, 1048655,
-	0x018f, 1048778,
-	0x0190, 1048779,
-	0x0191, 1048577,
-	0x0193, 1048781,
-	0x0194, 1048783,
-	0x0196, 1048787,
-	0x0197, 1048785,
-	0x0198, 1048577,
-	0x019c, 1048787,
-	0x019d, 1048789,
-	0x019f, 1048790,
-	0x01a0, 1048577,
-	0x01a2, 1048577,
-	0x01a4, 1048577,
-	0x01a6, 1048794,
-	0x01a7, 1048577,
-	0x01a9, 1048794,
-	0x01ac, 1048577,
-	0x01ae, 1048794,
-	0x01af, 1048577,
-	0x01b3, 1048577,
-	0x01b5, 1048577,
-	0x01b7, 1048795,
-	0x01b8, 1048577,
-	0x01bc, 1048577,
-	0x01c4, 1048578,
-	0x01c5, 1048577,
-	0x01c7, 1048578,
-	0x01c8, 1048577,
-	0x01ca, 1048578,
-	0x01cb, 1048577,
-	0x01cd, 1048577,
-	0x01cf, 1048577,
-	0x01d1, 1048577,
-	0x01d3, 1048577,
-	0x01d5, 1048577,
-	0x01d7, 1048577,
-	0x01d9, 1048577,
-	0x01db, 1048577,
-	0x01de, 1048577,
-	0x01e0, 1048577,
-	0x01e2, 1048577,
-	0x01e4, 1048577,
-	0x01e6, 1048577,
-	0x01e8, 1048577,
-	0x01ea, 1048577,
-	0x01ec, 1048577,
-	0x01ee, 1048577,
-	0x01f1, 1048578,
-	0x01f2, 1048577,
-	0x01f4, 1048577,
-	0x01f6, 1048479,
-	0x01f7, 1048520,
-	0x01f8, 1048577,
-	0x01fa, 1048577,
-	0x01fc, 1048577,
-	0x01fe, 1048577,
-	0x0200, 1048577,
-	0x0202, 1048577,
-	0x0204, 1048577,
-	0x0206, 1048577,
-	0x0208, 1048577,
-	0x020a, 1048577,
-	0x020c, 1048577,
-	0x020e, 1048577,
-	0x0210, 1048577,
-	0x0212, 1048577,
-	0x0214, 1048577,
-	0x0216, 1048577,
-	0x0218, 1048577,
-	0x021a, 1048577,
-	0x021c, 1048577,
-	0x021e, 1048577,
-	0x0220, 1048446,
-	0x0222, 1048577,
-	0x0224, 1048577,
-	0x0226, 1048577,
-	0x0228, 1048577,
-	0x022a, 1048577,
-	0x022c, 1048577,
-	0x022e, 1048577,
-	0x0230, 1048577,
-	0x0232, 1048577,
-	0x023a, 1059371,
-	0x023b, 1048577,
-	0x023d, 1048413,
-	0x023e, 1059368,
-	0x0241, 1048577,
-	0x0243, 1048381,
-	0x0244, 1048645,
-	0x0245, 1048647,
-	0x0246, 1048577,
-	0x0248, 1048577,
-	0x024a, 1048577,
-	0x024c, 1048577,
-	0x024e, 1048577,
-	0x0370, 1048577,
-	0x0372, 1048577,
-	0x0376, 1048577,
-	0x0386, 1048614,
-	0x038c, 1048640,
-	0x03cf, 1048584,
-	0x03d8, 1048577,
-	0x03da, 1048577,
-	0x03dc, 1048577,
-	0x03de, 1048577,
-	0x03e0, 1048577,
-	0x03e2, 1048577,
-	0x03e4, 1048577,
-	0x03e6, 1048577,
-	0x03e8, 1048577,
-	0x03ea, 1048577,
-	0x03ec, 1048577,
-	0x03ee, 1048577,
-	0x03f4, 1048516,
-	0x03f7, 1048577,
-	0x03f9, 1048569,
-	0x03fa, 1048577,
-	0x0460, 1048577,
-	0x0462, 1048577,
-	0x0464, 1048577,
-	0x0466, 1048577,
-	0x0468, 1048577,
-	0x046a, 1048577,
-	0x046c, 1048577,
-	0x046e, 1048577,
-	0x0470, 1048577,
-	0x0472, 1048577,
-	0x0474, 1048577,
-	0x0476, 1048577,
-	0x0478, 1048577,
-	0x047a, 1048577,
-	0x047c, 1048577,
-	0x047e, 1048577,
-	0x0480, 1048577,
-	0x048a, 1048577,
-	0x048c, 1048577,
-	0x048e, 1048577,
-	0x0490, 1048577,
-	0x0492, 1048577,
-	0x0494, 1048577,
-	0x0496, 1048577,
-	0x0498, 1048577,
-	0x049a, 1048577,
-	0x049c, 1048577,
-	0x049e, 1048577,
-	0x04a0, 1048577,
-	0x04a2, 1048577,
-	0x04a4, 1048577,
-	0x04a6, 1048577,
-	0x04a8, 1048577,
-	0x04aa, 1048577,
-	0x04ac, 1048577,
-	0x04ae, 1048577,
-	0x04b0, 1048577,
-	0x04b2, 1048577,
-	0x04b4, 1048577,
-	0x04b6, 1048577,
-	0x04b8, 1048577,
-	0x04ba, 1048577,
-	0x04bc, 1048577,
-	0x04be, 1048577,
-	0x04c0, 1048591,
-	0x04c1, 1048577,
-	0x04c3, 1048577,
-	0x04c5, 1048577,
-	0x04c7, 1048577,
-	0x04c9, 1048577,
-	0x04cb, 1048577,
-	0x04cd, 1048577,
-	0x04d0, 1048577,
-	0x04d2, 1048577,
-	0x04d4, 1048577,
-	0x04d6, 1048577,
-	0x04d8, 1048577,
-	0x04da, 1048577,
-	0x04dc, 1048577,
-	0x04de, 1048577,
-	0x04e0, 1048577,
-	0x04e2, 1048577,
-	0x04e4, 1048577,
-	0x04e6, 1048577,
-	0x04e8, 1048577,
-	0x04ea, 1048577,
-	0x04ec, 1048577,
-	0x04ee, 1048577,
-	0x04f0, 1048577,
-	0x04f2, 1048577,
-	0x04f4, 1048577,
-	0x04f6, 1048577,
-	0x04f8, 1048577,
-	0x04fa, 1048577,
-	0x04fc, 1048577,
-	0x04fe, 1048577,
-	0x0500, 1048577,
-	0x0502, 1048577,
-	0x0504, 1048577,
-	0x0506, 1048577,
-	0x0508, 1048577,
-	0x050a, 1048577,
-	0x050c, 1048577,
-	0x050e, 1048577,
-	0x0510, 1048577,
-	0x0512, 1048577,
-	0x0514, 1048577,
-	0x0516, 1048577,
-	0x0518, 1048577,
-	0x051a, 1048577,
-	0x051c, 1048577,
-	0x051e, 1048577,
-	0x0520, 1048577,
-	0x0522, 1048577,
-	0x0524, 1048577,
-	0x0526, 1048577,
-	0x10c7, 1055840,
-	0x10cd, 1055840,
-	0x1e00, 1048577,
-	0x1e02, 1048577,
-	0x1e04, 1048577,
-	0x1e06, 1048577,
-	0x1e08, 1048577,
-	0x1e0a, 1048577,
-	0x1e0c, 1048577,
-	0x1e0e, 1048577,
-	0x1e10, 1048577,
-	0x1e12, 1048577,
-	0x1e14, 1048577,
-	0x1e16, 1048577,
-	0x1e18, 1048577,
-	0x1e1a, 1048577,
-	0x1e1c, 1048577,
-	0x1e1e, 1048577,
-	0x1e20, 1048577,
-	0x1e22, 1048577,
-	0x1e24, 1048577,
-	0x1e26, 1048577,
-	0x1e28, 1048577,
-	0x1e2a, 1048577,
-	0x1e2c, 1048577,
-	0x1e2e, 1048577,
-	0x1e30, 1048577,
-	0x1e32, 1048577,
-	0x1e34, 1048577,
-	0x1e36, 1048577,
-	0x1e38, 1048577,
-	0x1e3a, 1048577,
-	0x1e3c, 1048577,
-	0x1e3e, 1048577,
-	0x1e40, 1048577,
-	0x1e42, 1048577,
-	0x1e44, 1048577,
-	0x1e46, 1048577,
-	0x1e48, 1048577,
-	0x1e4a, 1048577,
-	0x1e4c, 1048577,
-	0x1e4e, 1048577,
-	0x1e50, 1048577,
-	0x1e52, 1048577,
-	0x1e54, 1048577,
-	0x1e56, 1048577,
-	0x1e58, 1048577,
-	0x1e5a, 1048577,
-	0x1e5c, 1048577,
-	0x1e5e, 1048577,
-	0x1e60, 1048577,
-	0x1e62, 1048577,
-	0x1e64, 1048577,
-	0x1e66, 1048577,
-	0x1e68, 1048577,
-	0x1e6a, 1048577,
-	0x1e6c, 1048577,
-	0x1e6e, 1048577,
-	0x1e70, 1048577,
-	0x1e72, 1048577,
-	0x1e74, 1048577,
-	0x1e76, 1048577,
-	0x1e78, 1048577,
-	0x1e7a, 1048577,
-	0x1e7c, 1048577,
-	0x1e7e, 1048577,
-	0x1e80, 1048577,
-	0x1e82, 1048577,
-	0x1e84, 1048577,
-	0x1e86, 1048577,
-	0x1e88, 1048577,
-	0x1e8a, 1048577,
-	0x1e8c, 1048577,
-	0x1e8e, 1048577,
-	0x1e90, 1048577,
-	0x1e92, 1048577,
-	0x1e94, 1048577,
-	0x1e9e, 1040961,
-	0x1ea0, 1048577,
-	0x1ea2, 1048577,
-	0x1ea4, 1048577,
-	0x1ea6, 1048577,
-	0x1ea8, 1048577,
-	0x1eaa, 1048577,
-	0x1eac, 1048577,
-	0x1eae, 1048577,
-	0x1eb0, 1048577,
-	0x1eb2, 1048577,
-	0x1eb4, 1048577,
-	0x1eb6, 1048577,
-	0x1eb8, 1048577,
-	0x1eba, 1048577,
-	0x1ebc, 1048577,
-	0x1ebe, 1048577,
-	0x1ec0, 1048577,
-	0x1ec2, 1048577,
-	0x1ec4, 1048577,
-	0x1ec6, 1048577,
-	0x1ec8, 1048577,
-	0x1eca, 1048577,
-	0x1ecc, 1048577,
-	0x1ece, 1048577,
-	0x1ed0, 1048577,
-	0x1ed2, 1048577,
-	0x1ed4, 1048577,
-	0x1ed6, 1048577,
-	0x1ed8, 1048577,
-	0x1eda, 1048577,
-	0x1edc, 1048577,
-	0x1ede, 1048577,
-	0x1ee0, 1048577,
-	0x1ee2, 1048577,
-	0x1ee4, 1048577,
-	0x1ee6, 1048577,
-	0x1ee8, 1048577,
-	0x1eea, 1048577,
-	0x1eec, 1048577,
-	0x1eee, 1048577,
-	0x1ef0, 1048577,
-	0x1ef2, 1048577,
-	0x1ef4, 1048577,
-	0x1ef6, 1048577,
-	0x1ef8, 1048577,
-	0x1efa, 1048577,
-	0x1efc, 1048577,
-	0x1efe, 1048577,
-	0x1f59, 1048568,
-	0x1f5b, 1048568,
-	0x1f5d, 1048568,
-	0x1f5f, 1048568,
-	0x1fbc, 1048567,
-	0x1fcc, 1048567,
-	0x1fec, 1048569,
-	0x1ffc, 1048567,
-	0x2126, 1041059,
-	0x212a, 1040193,
-	0x212b, 1040314,
-	0x2132, 1048604,
-	0x2183, 1048577,
-	0x2c60, 1048577,
-	0x2c62, 1037833,
-	0x2c63, 1044762,
-	0x2c64, 1037849,
-	0x2c67, 1048577,
-	0x2c69, 1048577,
-	0x2c6b, 1048577,
-	0x2c6d, 1037796,
-	0x2c6e, 1037827,
-	0x2c6f, 1037793,
-	0x2c70, 1037794,
-	0x2c72, 1048577,
-	0x2c75, 1048577,
-	0x2c80, 1048577,
-	0x2c82, 1048577,
-	0x2c84, 1048577,
-	0x2c86, 1048577,
-	0x2c88, 1048577,
-	0x2c8a, 1048577,
-	0x2c8c, 1048577,
-	0x2c8e, 1048577,
-	0x2c90, 1048577,
-	0x2c92, 1048577,
-	0x2c94, 1048577,
-	0x2c96, 1048577,
-	0x2c98, 1048577,
-	0x2c9a, 1048577,
-	0x2c9c, 1048577,
-	0x2c9e, 1048577,
-	0x2ca0, 1048577,
-	0x2ca2, 1048577,
-	0x2ca4, 1048577,
-	0x2ca6, 1048577,
-	0x2ca8, 1048577,
-	0x2caa, 1048577,
-	0x2cac, 1048577,
-	0x2cae, 1048577,
-	0x2cb0, 1048577,
-	0x2cb2, 1048577,
-	0x2cb4, 1048577,
-	0x2cb6, 1048577,
-	0x2cb8, 1048577,
-	0x2cba, 1048577,
-	0x2cbc, 1048577,
-	0x2cbe, 1048577,
-	0x2cc0, 1048577,
-	0x2cc2, 1048577,
-	0x2cc4, 1048577,
-	0x2cc6, 1048577,
-	0x2cc8, 1048577,
-	0x2cca, 1048577,
-	0x2ccc, 1048577,
-	0x2cce, 1048577,
-	0x2cd0, 1048577,
-	0x2cd2, 1048577,
-	0x2cd4, 1048577,
-	0x2cd6, 1048577,
-	0x2cd8, 1048577,
-	0x2cda, 1048577,
-	0x2cdc, 1048577,
-	0x2cde, 1048577,
-	0x2ce0, 1048577,
-	0x2ce2, 1048577,
-	0x2ceb, 1048577,
-	0x2ced, 1048577,
-	0x2cf2, 1048577,
-	0xa640, 1048577,
-	0xa642, 1048577,
-	0xa644, 1048577,
-	0xa646, 1048577,
-	0xa648, 1048577,
-	0xa64a, 1048577,
-	0xa64c, 1048577,
-	0xa64e, 1048577,
-	0xa650, 1048577,
-	0xa652, 1048577,
-	0xa654, 1048577,
-	0xa656, 1048577,
-	0xa658, 1048577,
-	0xa65a, 1048577,
-	0xa65c, 1048577,
-	0xa65e, 1048577,
-	0xa660, 1048577,
-	0xa662, 1048577,
-	0xa664, 1048577,
-	0xa666, 1048577,
-	0xa668, 1048577,
-	0xa66a, 1048577,
-	0xa66c, 1048577,
-	0xa680, 1048577,
-	0xa682, 1048577,
-	0xa684, 1048577,
-	0xa686, 1048577,
-	0xa688, 1048577,
-	0xa68a, 1048577,
-	0xa68c, 1048577,
-	0xa68e, 1048577,
-	0xa690, 1048577,
-	0xa692, 1048577,
-	0xa694, 1048577,
-	0xa696, 1048577,
-	0xa722, 1048577,
-	0xa724, 1048577,
-	0xa726, 1048577,
-	0xa728, 1048577,
-	0xa72a, 1048577,
-	0xa72c, 1048577,
-	0xa72e, 1048577,
-	0xa732, 1048577,
-	0xa734, 1048577,
-	0xa736, 1048577,
-	0xa738, 1048577,
-	0xa73a, 1048577,
-	0xa73c, 1048577,
-	0xa73e, 1048577,
-	0xa740, 1048577,
-	0xa742, 1048577,
-	0xa744, 1048577,
-	0xa746, 1048577,
-	0xa748, 1048577,
-	0xa74a, 1048577,
-	0xa74c, 1048577,
-	0xa74e, 1048577,
-	0xa750, 1048577,
-	0xa752, 1048577,
-	0xa754, 1048577,
-	0xa756, 1048577,
-	0xa758, 1048577,
-	0xa75a, 1048577,
-	0xa75c, 1048577,
-	0xa75e, 1048577,
-	0xa760, 1048577,
-	0xa762, 1048577,
-	0xa764, 1048577,
-	0xa766, 1048577,
-	0xa768, 1048577,
-	0xa76a, 1048577,
-	0xa76c, 1048577,
-	0xa76e, 1048577,
-	0xa779, 1048577,
-	0xa77b, 1048577,
-	0xa77d, 1013244,
-	0xa77e, 1048577,
-	0xa780, 1048577,
-	0xa782, 1048577,
-	0xa784, 1048577,
-	0xa786, 1048577,
-	0xa78b, 1048577,
-	0xa78d, 1006296,
-	0xa790, 1048577,
-	0xa792, 1048577,
-	0xa7a0, 1048577,
-	0xa7a2, 1048577,
-	0xa7a4, 1048577,
-	0xa7a6, 1048577,
-	0xa7a8, 1048577,
-	0xa7aa, 1006268,
-};
-
-/* }}} */
-
-/* {{{ To title */
-
-static uint32_t totitler[] = {
-	0x0061, 0x007a, 1048544,
-	0x00e0, 0x00f6, 1048544,
-	0x00f8, 0x00fe, 1048544,
-	0x023f, 0x0240, 1059391,
-	0x0256, 0x0257, 1048371,
-	0x028a, 0x028b, 1048359,
-	0x037b, 0x037d, 1048706,
-	0x03ad, 0x03af, 1048539,
-	0x03b1, 0x03c1, 1048544,
-	0x03c3, 0x03cb, 1048544,
-	0x03cd, 0x03ce, 1048513,
-	0x0430, 0x044f, 1048544,
-	0x0450, 0x045f, 1048496,
-	0x0561, 0x0586, 1048528,
-	0x1f00, 0x1f07, 1048584,
-	0x1f10, 0x1f15, 1048584,
-	0x1f20, 0x1f27, 1048584,
-	0x1f30, 0x1f37, 1048584,
-	0x1f40, 0x1f45, 1048584,
-	0x1f60, 0x1f67, 1048584,
-	0x1f70, 0x1f71, 1048650,
-	0x1f72, 0x1f75, 1048662,
-	0x1f76, 0x1f77, 1048676,
-	0x1f78, 0x1f79, 1048704,
-	0x1f7a, 0x1f7b, 1048688,
-	0x1f7c, 0x1f7d, 1048702,
-	0x1f80, 0x1f87, 1048584,
-	0x1f90, 0x1f97, 1048584,
-	0x1fa0, 0x1fa7, 1048584,
-	0x1fb0, 0x1fb1, 1048584,
-	0x1fd0, 0x1fd1, 1048584,
-	0x1fe0, 0x1fe1, 1048584,
-	0x2170, 0x217f, 1048560,
-	0x24d0, 0x24e9, 1048550,
-	0x2c30, 0x2c5e, 1048528,
-	0x2d00, 0x2d25, 1041312,
-	0xff41, 0xff5a, 1048544,
-	0x10428, 0x1044f, 1048536,
-};
-
-static uint32_t totitles[] = {
-	0x00b5, 1049319,
-	0x00ff, 1048697,
-	0x0101, 1048575,
-	0x0103, 1048575,
-	0x0105, 1048575,
-	0x0107, 1048575,
-	0x0109, 1048575,
-	0x010b, 1048575,
-	0x010d, 1048575,
-	0x010f, 1048575,
-	0x0111, 1048575,
-	0x0113, 1048575,
-	0x0115, 1048575,
-	0x0117, 1048575,
-	0x0119, 1048575,
-	0x011b, 1048575,
-	0x011d, 1048575,
-	0x011f, 1048575,
-	0x0121, 1048575,
-	0x0123, 1048575,
-	0x0125, 1048575,
-	0x0127, 1048575,
-	0x0129, 1048575,
-	0x012b, 1048575,
-	0x012d, 1048575,
-	0x012f, 1048575,
-	0x0131, 1048344,
-	0x0133, 1048575,
-	0x0135, 1048575,
-	0x0137, 1048575,
-	0x013a, 1048575,
-	0x013c, 1048575,
-	0x013e, 1048575,
-	0x0140, 1048575,
-	0x0142, 1048575,
-	0x0144, 1048575,
-	0x0146, 1048575,
-	0x0148, 1048575,
-	0x014b, 1048575,
-	0x014d, 1048575,
-	0x014f, 1048575,
-	0x0151, 1048575,
-	0x0153, 1048575,
-	0x0155, 1048575,
-	0x0157, 1048575,
-	0x0159, 1048575,
-	0x015b, 1048575,
-	0x015d, 1048575,
-	0x015f, 1048575,
-	0x0161, 1048575,
-	0x0163, 1048575,
-	0x0165, 1048575,
-	0x0167, 1048575,
-	0x0169, 1048575,
-	0x016b, 1048575,
-	0x016d, 1048575,
-	0x016f, 1048575,
-	0x0171, 1048575,
-	0x0173, 1048575,
-	0x0175, 1048575,
-	0x0177, 1048575,
-	0x017a, 1048575,
-	0x017c, 1048575,
-	0x017e, 1048575,
-	0x017f, 1048276,
-	0x0180, 1048771,
-	0x0183, 1048575,
-	0x0185, 1048575,
-	0x0188, 1048575,
-	0x018c, 1048575,
-	0x0192, 1048575,
-	0x0195, 1048673,
-	0x0199, 1048575,
-	0x019a, 1048739,
-	0x019e, 1048706,
-	0x01a1, 1048575,
-	0x01a3, 1048575,
-	0x01a5, 1048575,
-	0x01a8, 1048575,
-	0x01ad, 1048575,
-	0x01b0, 1048575,
-	0x01b4, 1048575,
-	0x01b6, 1048575,
-	0x01b9, 1048575,
-	0x01bd, 1048575,
-	0x01bf, 1048632,
-	0x01c4, 1048577,
-	0x01c6, 1048575,
-	0x01c7, 1048577,
-	0x01c9, 1048575,
-	0x01ca, 1048577,
-	0x01cc, 1048575,
-	0x01ce, 1048575,
-	0x01d0, 1048575,
-	0x01d2, 1048575,
-	0x01d4, 1048575,
-	0x01d6, 1048575,
-	0x01d8, 1048575,
-	0x01da, 1048575,
-	0x01dc, 1048575,
-	0x01dd, 1048497,
-	0x01df, 1048575,
-	0x01e1, 1048575,
-	0x01e3, 1048575,
-	0x01e5, 1048575,
-	0x01e7, 1048575,
-	0x01e9, 1048575,
-	0x01eb, 1048575,
-	0x01ed, 1048575,
-	0x01ef, 1048575,
-	0x01f1, 1048577,
-	0x01f3, 1048575,
-	0x01f5, 1048575,
-	0x01f9, 1048575,
-	0x01fb, 1048575,
-	0x01fd, 1048575,
-	0x01ff, 1048575,
-	0x0201, 1048575,
-	0x0203, 1048575,
-	0x0205, 1048575,
-	0x0207, 1048575,
-	0x0209, 1048575,
-	0x020b, 1048575,
-	0x020d, 1048575,
-	0x020f, 1048575,
-	0x0211, 1048575,
-	0x0213, 1048575,
-	0x0215, 1048575,
-	0x0217, 1048575,
-	0x0219, 1048575,
-	0x021b, 1048575,
-	0x021d, 1048575,
-	0x021f, 1048575,
-	0x0223, 1048575,
-	0x0225, 1048575,
-	0x0227, 1048575,
-	0x0229, 1048575,
-	0x022b, 1048575,
-	0x022d, 1048575,
-	0x022f, 1048575,
-	0x0231, 1048575,
-	0x0233, 1048575,
-	0x023c, 1048575,
-	0x0242, 1048575,
-	0x0247, 1048575,
-	0x0249, 1048575,
-	0x024b, 1048575,
-	0x024d, 1048575,
-	0x024f, 1048575,
-	0x0250, 1059359,
-	0x0251, 1059356,
-	0x0252, 1059358,
-	0x0253, 1048366,
-	0x0254, 1048370,
-	0x0259, 1048374,
-	0x025b, 1048373,
-	0x0260, 1048371,
-	0x0263, 1048369,
-	0x0265, 1090856,
-	0x0266, 1090884,
-	0x0268, 1048367,
-	0x0269, 1048365,
-	0x026b, 1059319,
-	0x026f, 1048365,
-	0x0271, 1059325,
-	0x0272, 1048363,
-	0x0275, 1048362,
-	0x027d, 1059303,
-	0x0280, 1048358,
-	0x0283, 1048358,
-	0x0288, 1048358,
-	0x0289, 1048507,
-	0x028c, 1048505,
-	0x0292, 1048357,
-	0x0345, 1048660,
-	0x0371, 1048575,
-	0x0373, 1048575,
-	0x0377, 1048575,
-	0x03ac, 1048538,
-	0x03c2, 1048545,
-	0x03cc, 1048512,
-	0x03d0, 1048514,
-	0x03d1, 1048519,
-	0x03d5, 1048529,
-	0x03d6, 1048522,
-	0x03d7, 1048568,
-	0x03d9, 1048575,
-	0x03db, 1048575,
-	0x03dd, 1048575,
-	0x03df, 1048575,
-	0x03e1, 1048575,
-	0x03e3, 1048575,
-	0x03e5, 1048575,
-	0x03e7, 1048575,
-	0x03e9, 1048575,
-	0x03eb, 1048575,
-	0x03ed, 1048575,
-	0x03ef, 1048575,
-	0x03f0, 1048490,
-	0x03f1, 1048496,
-	0x03f2, 1048583,
-	0x03f5, 1048480,
-	0x03f8, 1048575,
-	0x03fb, 1048575,
-	0x0461, 1048575,
-	0x0463, 1048575,
-	0x0465, 1048575,
-	0x0467, 1048575,
-	0x0469, 1048575,
-	0x046b, 1048575,
-	0x046d, 1048575,
-	0x046f, 1048575,
-	0x0471, 1048575,
-	0x0473, 1048575,
-	0x0475, 1048575,
-	0x0477, 1048575,
-	0x0479, 1048575,
-	0x047b, 1048575,
-	0x047d, 1048575,
-	0x047f, 1048575,
-	0x0481, 1048575,
-	0x048b, 1048575,
-	0x048d, 1048575,
-	0x048f, 1048575,
-	0x0491, 1048575,
-	0x0493, 1048575,
-	0x0495, 1048575,
-	0x0497, 1048575,
-	0x0499, 1048575,
-	0x049b, 1048575,
-	0x049d, 1048575,
-	0x049f, 1048575,
-	0x04a1, 1048575,
-	0x04a3, 1048575,
-	0x04a5, 1048575,
-	0x04a7, 1048575,
-	0x04a9, 1048575,
-	0x04ab, 1048575,
-	0x04ad, 1048575,
-	0x04af, 1048575,
-	0x04b1, 1048575,
-	0x04b3, 1048575,
-	0x04b5, 1048575,
-	0x04b7, 1048575,
-	0x04b9, 1048575,
-	0x04bb, 1048575,
-	0x04bd, 1048575,
-	0x04bf, 1048575,
-	0x04c2, 1048575,
-	0x04c4, 1048575,
-	0x04c6, 1048575,
-	0x04c8, 1048575,
-	0x04ca, 1048575,
-	0x04cc, 1048575,
-	0x04ce, 1048575,
-	0x04cf, 1048561,
-	0x04d1, 1048575,
-	0x04d3, 1048575,
-	0x04d5, 1048575,
-	0x04d7, 1048575,
-	0x04d9, 1048575,
-	0x04db, 1048575,
-	0x04dd, 1048575,
-	0x04df, 1048575,
-	0x04e1, 1048575,
-	0x04e3, 1048575,
-	0x04e5, 1048575,
-	0x04e7, 1048575,
-	0x04e9, 1048575,
-	0x04eb, 1048575,
-	0x04ed, 1048575,
-	0x04ef, 1048575,
-	0x04f1, 1048575,
-	0x04f3, 1048575,
-	0x04f5, 1048575,
-	0x04f7, 1048575,
-	0x04f9, 1048575,
-	0x04fb, 1048575,
-	0x04fd, 1048575,
-	0x04ff, 1048575,
-	0x0501, 1048575,
-	0x0503, 1048575,
-	0x0505, 1048575,
-	0x0507, 1048575,
-	0x0509, 1048575,
-	0x050b, 1048575,
-	0x050d, 1048575,
-	0x050f, 1048575,
-	0x0511, 1048575,
-	0x0513, 1048575,
-	0x0515, 1048575,
-	0x0517, 1048575,
-	0x0519, 1048575,
-	0x051b, 1048575,
-	0x051d, 1048575,
-	0x051f, 1048575,
-	0x0521, 1048575,
-	0x0523, 1048575,
-	0x0525, 1048575,
-	0x0527, 1048575,
-	0x1d79, 1083908,
-	0x1d7d, 1052390,
-	0x1e01, 1048575,
-	0x1e03, 1048575,
-	0x1e05, 1048575,
-	0x1e07, 1048575,
-	0x1e09, 1048575,
-	0x1e0b, 1048575,
-	0x1e0d, 1048575,
-	0x1e0f, 1048575,
-	0x1e11, 1048575,
-	0x1e13, 1048575,
-	0x1e15, 1048575,
-	0x1e17, 1048575,
-	0x1e19, 1048575,
-	0x1e1b, 1048575,
-	0x1e1d, 1048575,
-	0x1e1f, 1048575,
-	0x1e21, 1048575,
-	0x1e23, 1048575,
-	0x1e25, 1048575,
-	0x1e27, 1048575,
-	0x1e29, 1048575,
-	0x1e2b, 1048575,
-	0x1e2d, 1048575,
-	0x1e2f, 1048575,
-	0x1e31, 1048575,
-	0x1e33, 1048575,
-	0x1e35, 1048575,
-	0x1e37, 1048575,
-	0x1e39, 1048575,
-	0x1e3b, 1048575,
-	0x1e3d, 1048575,
-	0x1e3f, 1048575,
-	0x1e41, 1048575,
-	0x1e43, 1048575,
-	0x1e45, 1048575,
-	0x1e47, 1048575,
-	0x1e49, 1048575,
-	0x1e4b, 1048575,
-	0x1e4d, 1048575,
-	0x1e4f, 1048575,
-	0x1e51, 1048575,
-	0x1e53, 1048575,
-	0x1e55, 1048575,
-	0x1e57, 1048575,
-	0x1e59, 1048575,
-	0x1e5b, 1048575,
-	0x1e5d, 1048575,
-	0x1e5f, 1048575,
-	0x1e61, 1048575,
-	0x1e63, 1048575,
-	0x1e65, 1048575,
-	0x1e67, 1048575,
-	0x1e69, 1048575,
-	0x1e6b, 1048575,
-	0x1e6d, 1048575,
-	0x1e6f, 1048575,
-	0x1e71, 1048575,
-	0x1e73, 1048575,
-	0x1e75, 1048575,
-	0x1e77, 1048575,
-	0x1e79, 1048575,
-	0x1e7b, 1048575,
-	0x1e7d, 1048575,
-	0x1e7f, 1048575,
-	0x1e81, 1048575,
-	0x1e83, 1048575,
-	0x1e85, 1048575,
-	0x1e87, 1048575,
-	0x1e89, 1048575,
-	0x1e8b, 1048575,
-	0x1e8d, 1048575,
-	0x1e8f, 1048575,
-	0x1e91, 1048575,
-	0x1e93, 1048575,
-	0x1e95, 1048575,
-	0x1e9b, 1048517,
-	0x1ea1, 1048575,
-	0x1ea3, 1048575,
-	0x1ea5, 1048575,
-	0x1ea7, 1048575,
-	0x1ea9, 1048575,
-	0x1eab, 1048575,
-	0x1ead, 1048575,
-	0x1eaf, 1048575,
-	0x1eb1, 1048575,
-	0x1eb3, 1048575,
-	0x1eb5, 1048575,
-	0x1eb7, 1048575,
-	0x1eb9, 1048575,
-	0x1ebb, 1048575,
-	0x1ebd, 1048575,
-	0x1ebf, 1048575,
-	0x1ec1, 1048575,
-	0x1ec3, 1048575,
-	0x1ec5, 1048575,
-	0x1ec7, 1048575,
-	0x1ec9, 1048575,
-	0x1ecb, 1048575,
-	0x1ecd, 1048575,
-	0x1ecf, 1048575,
-	0x1ed1, 1048575,
-	0x1ed3, 1048575,
-	0x1ed5, 1048575,
-	0x1ed7, 1048575,
-	0x1ed9, 1048575,
-	0x1edb, 1048575,
-	0x1edd, 1048575,
-	0x1edf, 1048575,
-	0x1ee1, 1048575,
-	0x1ee3, 1048575,
-	0x1ee5, 1048575,
-	0x1ee7, 1048575,
-	0x1ee9, 1048575,
-	0x1eeb, 1048575,
-	0x1eed, 1048575,
-	0x1eef, 1048575,
-	0x1ef1, 1048575,
-	0x1ef3, 1048575,
-	0x1ef5, 1048575,
-	0x1ef7, 1048575,
-	0x1ef9, 1048575,
-	0x1efb, 1048575,
-	0x1efd, 1048575,
-	0x1eff, 1048575,
-	0x1f51, 1048584,
-	0x1f53, 1048584,
-	0x1f55, 1048584,
-	0x1f57, 1048584,
-	0x1fb3, 1048585,
-	0x1fbe, 1041371,
-	0x1fc3, 1048585,
-	0x1fe5, 1048583,
-	0x1ff3, 1048585,
-	0x214e, 1048548,
-	0x2184, 1048575,
-	0x2c61, 1048575,
-	0x2c65, 1037781,
-	0x2c66, 1037784,
-	0x2c68, 1048575,
-	0x2c6a, 1048575,
-	0x2c6c, 1048575,
-	0x2c73, 1048575,
-	0x2c76, 1048575,
-	0x2c81, 1048575,
-	0x2c83, 1048575,
-	0x2c85, 1048575,
-	0x2c87, 1048575,
-	0x2c89, 1048575,
-	0x2c8b, 1048575,
-	0x2c8d, 1048575,
-	0x2c8f, 1048575,
-	0x2c91, 1048575,
-	0x2c93, 1048575,
-	0x2c95, 1048575,
-	0x2c97, 1048575,
-	0x2c99, 1048575,
-	0x2c9b, 1048575,
-	0x2c9d, 1048575,
-	0x2c9f, 1048575,
-	0x2ca1, 1048575,
-	0x2ca3, 1048575,
-	0x2ca5, 1048575,
-	0x2ca7, 1048575,
-	0x2ca9, 1048575,
-	0x2cab, 1048575,
-	0x2cad, 1048575,
-	0x2caf, 1048575,
-	0x2cb1, 1048575,
-	0x2cb3, 1048575,
-	0x2cb5, 1048575,
-	0x2cb7, 1048575,
-	0x2cb9, 1048575,
-	0x2cbb, 1048575,
-	0x2cbd, 1048575,
-	0x2cbf, 1048575,
-	0x2cc1, 1048575,
-	0x2cc3, 1048575,
-	0x2cc5, 1048575,
-	0x2cc7, 1048575,
-	0x2cc9, 1048575,
-	0x2ccb, 1048575,
-	0x2ccd, 1048575,
-	0x2ccf, 1048575,
-	0x2cd1, 1048575,
-	0x2cd3, 1048575,
-	0x2cd5, 1048575,
-	0x2cd7, 1048575,
-	0x2cd9, 1048575,
-	0x2cdb, 1048575,
-	0x2cdd, 1048575,
-	0x2cdf, 1048575,
-	0x2ce1, 1048575,
-	0x2ce3, 1048575,
-	0x2cec, 1048575,
-	0x2cee, 1048575,
-	0x2cf3, 1048575,
-	0x2d27, 1041312,
-	0x2d2d, 1041312,
-	0xa641, 1048575,
-	0xa643, 1048575,
-	0xa645, 1048575,
-	0xa647, 1048575,
-	0xa649, 1048575,
-	0xa64b, 1048575,
-	0xa64d, 1048575,
-	0xa64f, 1048575,
-	0xa651, 1048575,
-	0xa653, 1048575,
-	0xa655, 1048575,
-	0xa657, 1048575,
-	0xa659, 1048575,
-	0xa65b, 1048575,
-	0xa65d, 1048575,
-	0xa65f, 1048575,
-	0xa661, 1048575,
-	0xa663, 1048575,
-	0xa665, 1048575,
-	0xa667, 1048575,
-	0xa669, 1048575,
-	0xa66b, 1048575,
-	0xa66d, 1048575,
-	0xa681, 1048575,
-	0xa683, 1048575,
-	0xa685, 1048575,
-	0xa687, 1048575,
-	0xa689, 1048575,
-	0xa68b, 1048575,
-	0xa68d, 1048575,
-	0xa68f, 1048575,
-	0xa691, 1048575,
-	0xa693, 1048575,
-	0xa695, 1048575,
-	0xa697, 1048575,
-	0xa723, 1048575,
-	0xa725, 1048575,
-	0xa727, 1048575,
-	0xa729, 1048575,
-	0xa72b, 1048575,
-	0xa72d, 1048575,
-	0xa72f, 1048575,
-	0xa733, 1048575,
-	0xa735, 1048575,
-	0xa737, 1048575,
-	0xa739, 1048575,
-	0xa73b, 1048575,
-	0xa73d, 1048575,
-	0xa73f, 1048575,
-	0xa741, 1048575,
-	0xa743, 1048575,
-	0xa745, 1048575,
-	0xa747, 1048575,
-	0xa749, 1048575,
-	0xa74b, 1048575,
-	0xa74d, 1048575,
-	0xa74f, 1048575,
-	0xa751, 1048575,
-	0xa753, 1048575,
-	0xa755, 1048575,
-	0xa757, 1048575,
-	0xa759, 1048575,
-	0xa75b, 1048575,
-	0xa75d, 1048575,
-	0xa75f, 1048575,
-	0xa761, 1048575,
-	0xa763, 1048575,
-	0xa765, 1048575,
-	0xa767, 1048575,
-	0xa769, 1048575,
-	0xa76b, 1048575,
-	0xa76d, 1048575,
-	0xa76f, 1048575,
-	0xa77a, 1048575,
-	0xa77c, 1048575,
-	0xa77f, 1048575,
-	0xa781, 1048575,
-	0xa783, 1048575,
-	0xa785, 1048575,
-	0xa787, 1048575,
-	0xa78c, 1048575,
-	0xa791, 1048575,
-	0xa793, 1048575,
-	0xa7a1, 1048575,
-	0xa7a3, 1048575,
-	0xa7a5, 1048575,
-	0xa7a7, 1048575,
-	0xa7a9, 1048575,
-};
-
-/* }}} */
-
-}
-
-void Utf8::encode(uint32_t c, char res[5])
-{
-	switch (nbytesPoint(c)) {
-	case 1:
-		res[0] = c;
-		res[1] = '\0';
-		break;
-	case 2:
-		res[0] = 0xC0 | ((c >> 6)  & 0x1F);
-		res[1] = 0x80 | (c & 0x3F);
-		res[2] = '\0';
-		break;
-	case 3:
-		res[0] = 0xE0 | ((c >> 12) & 0xF );
-		res[1] = 0x80 | ((c >> 6)  & 0x3F);
-		res[2] = 0x80 | (c & 0x3F);
-		res[3] = '\0';
-		break;
-	case 4:
-		res[0] = 0xF0 | ((c >> 18) & 0x7 );
-		res[1] = 0x80 | ((c >> 12) & 0x3F);
-		res[2] = 0x80 | ((c >> 6)  & 0x3F);
-		res[3] = 0x80 | (c & 0x3F);
-		res[4] = '\0';
-		break;
-	default:
-		break;
-	}
-}
-
-void Utf8::decode(uint32_t &c, const char *res)
-{
-	switch (nbytesUtf8(res[0])) {
-	case 1:
-		c = res[0];
-		break;
-	case 2:
-		c = res[0] & 0x1F;
-		c = (c << 6) | (res[1] & 0x3F);
-		break;
-	case 3:
-		c = res[0] & 0x1F;
-		c = (c << 6) | (res[1] & 0x3F);
-		c = (c << 6) | (res[2] & 0x3F);
-		break;
-	case 4:
-		c = res[0] & 0x1F;
-		c = (c << 6) | (res[1] & 0x3F);
-		c = (c << 6) | (res[2] & 0x3F);
-		c = (c << 6) | (res[3] & 0x3F);
-		break;
-	default:
-		break;
-	}
-}
-
-int8_t Utf8::nbytesUtf8(uint8_t c)
-{
-	if (c <= 0x7F)
-		return 1;
-	if ((c & 0xE0) == 0xC0)
-		return 2;
-	if ((c & 0xF0) == 0xE0)
-		return 3;
-	if ((c & 0xF8) == 0xF0)
-		return 4;
-
-	return -1;
-}
-
-int8_t Utf8::nbytesPoint(uint32_t c)
-{
-	if (c <= 0x7F)
-		return 1;
-	if (c <= 0x7FF)
-		return 2;
-	if (c <= 0xFFFF)
-		return 3;
-	if (c <= 0x1FFFFF)
-		return 4;
-
-	return -1;
-}
-
-size_t Utf8::length(const std::string &str)
-{
-	size_t total = 0;
-
-	for (size_t i = 0; i < str.size(); ) {
-		auto size = nbytesUtf8(str[i]);
-
-		if (size < 0)
-			throw std::invalid_argument("invalid sequence");
-
-		total ++;
-		i += size;
-	}
-
-	return total;
-}
-
-std::string Utf8::toutf8(const std::u32string &array)
-{
-	std::string res;
-
-	for (size_t i = 0; i < array.size(); ++i) {
-		char tmp[5];
-		auto size = nbytesPoint(array[i]);
-
-		if (size < 0)
-			throw std::invalid_argument("invalid sequence");
-
-		encode(array[i], tmp);
-		res.insert(res.length(), tmp);
-	}
-
-	return res;
-}
-
-std::u32string Utf8::toutf32(const std::string &str)
-{
-	std::u32string res;
-
-	for (size_t i = 0; i < str.size(); ) {
-		uint32_t point;
-		auto size = nbytesUtf8(str[i]);
-
-		if (size < 0)
-			throw std::invalid_argument("invalid sequence");
-
-		decode(point, str.data() + i);
-		res.push_back(point);
-		i += size;
-	}
-
-	return res;
-}
-
-bool Utf8::isspace(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, isspacer, LEN(isspacer) / 2, 2);
-	if (p && c >= p[0] && c <= p[1])
-		return true;
-
-	return false;
-}
-
-bool Utf8::isdigit(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, isdigitr, LEN(isdigitr) / 2, 2);
-	if (p && c >= p[0] && c <= p[1])
-		return true;
-
-	return false;
-}
-
-bool Utf8::isletter(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, isalphar, LEN(isalphar) / 2, 2);
-	if (p && c >= p[0] && c <= p[1])
-		return true;
-
-	p = rbsearch(c, isalphas, LEN(isalphas), 1);
-	if (p && c == p[0])
-		return true;
-
-	return false;
-}
-
-bool Utf8::isupper(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, isupperr, LEN(isupperr) / 2, 2);
-	if (p && c >= p[0] && c <= p[1])
-		return true;
-
-	p = rbsearch(c, isuppers, LEN(isuppers), 1);
-	if (p && c == p[0])
-		return true;
-
-	return false;
-}
-
-bool Utf8::islower(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, islowerr, LEN(islowerr) / 2, 2);
-	if (p && c >= p[0] && c <= p[1])
-		return true;
-
-	p = rbsearch(c, islowers, LEN(islowers), 1);
-	if (p && c == p[0])
-		return true;
-
-	return false;
-}
-
-bool Utf8::istitle(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, istitler, LEN(istitler) / 2, 2);
-	if (p && c >= p[0] && c <= p[1])
-		return true;
-
-	p = rbsearch(c, istitles, LEN(istitles), 1);
-	if(p && c == p[0])
-		return true;
-
-	return false;
-}
-
-uint32_t Utf8::toupper(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, toupperr, LEN(toupperr) / 3, 3);
-	if (p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-
-	p = rbsearch(c, touppers, LEN(touppers) / 2, 2);
-	if (p && c == p[0])
-		return c + p[1] - 1048576;
-
-	return c;
-}
-
-uint32_t Utf8::tolower(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, tolowerr, LEN(tolowerr) / 3, 3);
-	if (p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-
-	p = rbsearch(c, tolowers, LEN(tolowers) / 2, 2);
-	if (p && c == p[0])
-		return c + p[1] - 1048576;
-	
-	return c;
-}
-
-uint32_t Utf8::totitle(uint32_t c)
-{
-	uint32_t *p;
-
-	p = rbsearch(c, totitler, LEN(totitler) / 3, 3);
-	if (p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-
-	p = rbsearch(c, totitles, LEN(totitles) / 2, 2);
-	if (p && c == p[0])
-		return c + p[1] - 1048576;
-
-	return c;
-}
--- a/C++/Utf8.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,212 +0,0 @@
-/*
- * Utf8.h -- UTF-8 to UTF-32 conversions
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _UTF8_H_
-#define _UTF8_H_
-
-/**
- * @file Utf8.h
- * @brief UTF-8 to UTF-32 conversions
- */
-
-#include <cstdint>
-#include <stdexcept>
-#include <string>
-
-/**
- * @class Utf8
- * @brief Conversion between UTF-8 and UTF-32
- */
-class Utf8 {
-private:
-	static void encode(uint32_t point, char res[5]);
-	static void decode(uint32_t &c, const char *res);
-
-public:
-	/**
-	 * Get the number of bytes for the first multi byte character from a
-	 * utf-8 string.
-	 *
-	 * @param c the first multi byte character
-	 * @return the number of bytes [1-4] or -1 on invalid
-	 */
-	static int8_t nbytesUtf8(uint8_t c);
-
-	/**
-	 * Get the number of bytes for the unicode point.
-	 *
-	 * @param point the unicode point
-	 * @return the number of bytes [1-4] or -1 on invalid
-	 */
-	static int8_t nbytesPoint(uint32_t point);
-
-	/**
-	 * Get real number of character in a string.
-	 *
-	 * @param str the string
-	 * @return the length
-	 * @throw std::invalid_argument on invalid sequence
-	 */
-	static size_t length(const std::string &str);
-
-	/**
-	 * Convert a UTF-32 string to UTF-8 string.
-	 *
-	 * @param array the UTF-32 string
-	 * @return the UTF-8 string
-	 * @throw std::invalid_argument on invalid sequence
-	 */
-	static std::string toutf8(const std::u32string &array);
-
-	/**
-	 * Convert a UTF-8 string to UTF-32 string.
-	 *
-	 * @param str the UTF-8 string
-	 * @return the UTF-32 string
-	 * @throw std::invalid_argument on invalid sequence
-	 */
-	static std::u32string toutf32(const std::string &str);
-
-	/**
-	 * Check if the unicode character is space.
-	 *
-	 * @param c the character
-	 * @return true if space
-	 */
-	static bool isspace(uint32_t c);
-
-	/**
-	 * Check if the unicode character is digit.
-	 *
-	 * @param c the character
-	 * @return true if digit
-	 */
-	static bool isdigit(uint32_t c);
-
-	/**
-	 * Check if the unicode character is letter.
-	 *
-	 * @param c the character
-	 * @return true if letter
-	 */
-	static bool isletter(uint32_t c);
-
-	/**
-	 * Check if the unicode character is upper case.
-	 *
-	 * @param c the character
-	 * @return true if upper case
-	 */
-	static bool isupper(uint32_t c);
-
-	/**
-	 * Check if the unicode character is lower case.
-	 *
-	 * @param c the character
-	 * @return true if lower case
-	 */
-	static bool islower(uint32_t c);
-
-	/**
-	 * Check if the unicode character is title case.
-	 *
-	 * @param c the character
-	 * @return true if title case
-	 */
-	static bool istitle(uint32_t c);
-
-	/**
-	 * Convert to upper case.
-	 *
-	 * @param c the character
-	 * @return the upper case character
-	 */
-	static uint32_t toupper(uint32_t c);
-
-	/**
-	 * Convert to lower case.
-	 *
-	 * @param c the character
-	 * @return the lower case character
-	 */
-	static uint32_t tolower(uint32_t c);
-
-	/**
-	 * Convert to title case.
-	 *
-	 * @param c the character
-	 * @return the title case character
-	 */
-	static uint32_t totitle(uint32_t c);
-
-	/**
-	 * Convert the UTF-8 string to upper case.
-	 *
-	 * @param str the str
-	 * @return the upper case string
-	 */
-	static inline std::string toupper(const std::string &str)
-	{
-		return toutf8(toupper(toutf32(str)));
-	}
-
-	/**
-	 * Convert the UTF-32 string to upper case.
-	 *
-	 * @param str the str
-	 * @return the upper case string
-	 */
-	static inline std::u32string toupper(const std::u32string &str)
-	{
-		auto copy = str;
-
-		for (size_t i = 0; i < str.size(); ++i)
-			copy[i] = toupper(str[i]);
-
-		return copy;
-	}
-
-	/**
-	 * Convert the UTF-8 string to lower case.
-	 *
-	 * @param str the str
-	 * @return the lower case string
-	 */
-	static inline std::string tolower(const std::string &str)
-	{
-		return toutf8(tolower(toutf32(str)));
-	}
-
-	/**
-	 * Convert the UTF-32 string to lower case.
-	 *
-	 * @param str the str
-	 * @return the lower case string
-	 */
-	static inline std::u32string tolower(const std::u32string &str)
-	{
-		auto copy = str;
-
-		for (size_t i = 0; i < str.size(); ++i)
-			copy[i] = tolower(str[i]);
-
-		return copy;
-	}
-};
-
-#endif // !_UTF8_H_
--- a/C++/Xdg.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Xdg.cpp -- XDG directory specifications
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cstdlib>
-#include <stdexcept>
-#include <sstream>
-
-#include "Xdg.h"
-
-namespace {
-
-bool isabsolute(const std::string &path)
-{
-	return path.length() > 0 && path[0] == '/';
-}
-
-std::vector<std::string> split(const std::string &arg)
-{
-	std::stringstream iss(arg);
-	std::string item;
-	std::vector<std::string> elems;
-
-	while (std::getline(iss, item, ':'))
-		if (isabsolute(item))
-			elems.push_back(item);
-
-	return elems;
-}
-
-std::string envOrHome(const std::string &var, const std::string &repl)
-{
-	auto value = getenv(var.c_str());
-
-	if (value == nullptr || !isabsolute(value)) {
-		auto home = getenv("HOME");
-
-		if (home == nullptr)
-			throw std::runtime_error("could not get home directory");
-
-		return std::string(home) + "/" + repl;
-	}
-
-	return value;
-}
-
-std::vector<std::string> listOrDefaults(const std::string &var, const std::vector<std::string> &list)
-{
-	auto value = getenv(var.c_str());
-
-	if (!value)
-		return list;
-
-	// No valid item at all? Use defaults
-	auto result = split(value);
-
-	return (result.size() == 0) ? list : result;
-}
-
-} // !namespace
-
-Xdg::Xdg()
-{
-	m_configHome	= envOrHome("XDG_CONFIG_HOME", ".config");
-	m_dataHome	= envOrHome("XDG_DATA_HOME", ".local/share");
-	m_cacheHome	= envOrHome("XDG_CACHE_HOME", ".cache");
-
-	m_configDirs	= listOrDefaults("XDG_CONFIG_DIRS", { "/etc/xdg" });
-	m_dataDirs	= listOrDefaults("XDG_DATA_DIRS", { "/usr/local/share", "/usr/share" });
-
-	/*
-	 * Runtime directory is a special case and does not have a replacement, the
-	 * application should manage this by itself.
-	 */
-	auto runtime = getenv("XDG_RUNTIME_DIR");
-	if (runtime && isabsolute(runtime))
-		m_runtimeDir = runtime;
-}
-
-const std::string &Xdg::configHome() const noexcept
-{
-	return m_configHome;
-}
-
-const std::string &Xdg::dataHome() const noexcept
-{
-	return m_dataHome;
-}
-
-const std::string &Xdg::cacheHome() const noexcept
-{
-	return m_cacheHome;
-}
-
-const std::string &Xdg::runtimeDir() const
-{
-	if (m_runtimeDir.size() == 0)
-		throw std::runtime_error("XDG_RUNTIME_DIR is not set");
-
-	return m_runtimeDir;
-}
-
-const Xdg::List &Xdg::configDirs() const noexcept
-{
-	return m_configDirs;
-}
-
-const Xdg::List &Xdg::dataDirs() const noexcept
-{
-	return m_dataDirs;
-}
--- a/C++/Xdg.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Xdg.h -- XDG directory specifications
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _XDG_H_
-#define _XDG_H_
-
-#include <vector>
-#include <string>
-
-#if defined(_WIN32)
-#  if defined(BUILDING_DLL)
-#    define EXPORT __declspec(dllexport)
-#  else
-#    define EXPORT __declspec(dllimport)
-#  endif
-#else
-#  define EXPORT
-#endif
-
-/**
- * @class Xdg
- * @brief XDG specifications
- *
- * Read and get XDG directories. This file contains exports thingies so it can
- * compiles successfully on Windows but its usage is discouraged.
- */
-class EXPORT Xdg {
-public:
-	using List	= std::vector<std::string>;
-
-private:
-	std::string	m_configHome;
-	std::string	m_dataHome;
-	std::string	m_cacheHome;
-	std::string	m_runtimeDir;
-	List		m_configDirs;
-	List		m_dataDirs;
-
-public:
-	/**
-	 * Open an xdg instance and load directories.
-	 *
-	 * @throw std::runtime_error on failures
-	 */
-	Xdg();
-
-	/**
-	 * Get the config directory. ${XDG_CONFIG_HOME} or ${HOME}/.config
-	 *
-	 * @return the config directory
-	 */
-	const std::string &configHome() const noexcept;
-
-	/**
-	 * Get the data directory. ${XDG_DATA_HOME} or ${HOME}/.local/share
-	 *
-	 * @return the data directory
-	 */
-	const std::string &dataHome() const noexcept;
-
-	/**
-	 * Get the cache directory. ${XDG_CACHE_HOME} or ${HOME}/.cache
-	 *
-	 * @return the cache directory
-	 */
-	const std::string &cacheHome() const noexcept;
-
-	/**
-	 * Get the runtime directory. ${XDG_RUNTIME_DIR} must be set,
-	 * if not, it throws an exception.
-	 *
-	 * The XDG standard says that application should handle XDG_RUNTIME_DIR by
-	 * themselves.
-	 *
-	 * @return the runtime directory
-	 * @throw std::runtime_error on error
-	 */
-	const std::string &runtimeDir() const;
-
-	/**
-	 * Get the standard config directories. ${XDG_CONFIG_DIRS} or { "/etc/xdg" }
-	 *
-	 * @return the list of config directories
-	 */
-	const List &configDirs() const noexcept;
-
-	/**
-	 * Get the data directories. ${XDG_DATA_DIRS} or { "/usr/local/share", "/usr/share" }
-	 *
-	 * @return the list of data directories
-	 */
-	const List &dataDirs() const noexcept;
-};
-
-#endif // !_XDG_H_
--- a/C++/ZipArchive.cpp	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,295 +0,0 @@
-/*
- * ZipArchive.cpp -- wrapper around libzip
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cerrno>
-#include <cstdlib>
-#include <cstring>
-#include <stdexcept>
-
-#include "ZipArchive.h"
-
-namespace source {
-
-/* --------------------------------------------------------
- * Buffer (zip_source_buffer)
- * -------------------------------------------------------- */
-
-Buffer::Buffer(std::string data)
-	: m_data(std::move(data))
-{
-}
-
-struct zip_source *Buffer::source(struct zip *archive) const
-{
-	auto size = m_data.size();
-	auto data = static_cast<char *>(std::malloc(size));
-
-	if (data == nullptr)
-		throw std::runtime_error(std::strerror(errno));
-
-	std::memcpy(data, m_data.data(), size);
-
-	auto src = zip_source_buffer(archive, data, size, 1);
-
-	if (src == nullptr) {
-		std::free(data);
-		throw std::runtime_error(zip_strerror(archive));
-	}
-
-	return src;
-}
-
-/* --------------------------------------------------------
- * File (zip_source_file)
- * -------------------------------------------------------- */
-
-File::File(std::string path, ZipUint64 start, ZipInt64 length)
-	: m_path(std::move(path))
-	, m_start(start)
-	, m_length(length)
-{
-}
-
-struct zip_source *File::source(struct zip *archive) const
-{
-	auto src = zip_source_file(archive, m_path.c_str(), m_start, m_length);
-
-	if (src == nullptr)
-		throw std::runtime_error(zip_strerror(archive));
-
-	return src;
-}
-
-} // !source
-
-/* --------------------------------------------------------
- * ZipArchive
- * ------------------------------------------------------- */
-
-ZipArchive::ZipArchive(const std::string &path, ZipFlags flags)
-	: m_handle(nullptr, nullptr)
-{
-	int error;
-	struct zip *archive = zip_open(path.c_str(), flags, &error);
-
-	if (archive == nullptr)
-	{
-		char buf[128]{};
-
-		zip_error_to_str(buf, sizeof (buf), error, errno);
-
-		throw std::runtime_error(buf);
-	}
-
-	m_handle = { archive, zip_close };
-}
-
-void ZipArchive::setFileComment(ZipUint64 index, const std::string &text, ZipFlags flags)
-{
-	auto size = text.size();
-	auto cstr = (size == 0) ? nullptr : text.c_str();
-
-	if (zip_file_set_comment(m_handle.get(), index, cstr, size, flags) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-std::string ZipArchive::getFileComment(ZipUint64 index, ZipFlags flags) const
-{
-	zip_uint32_t length{};
-	auto text = zip_file_get_comment(m_handle.get(), index, &length, flags);
-
-	if (text == nullptr)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return { text, length };
-}
-
-void ZipArchive::setComment(const std::string &comment)
-{
-	if (zip_set_archive_comment(m_handle.get(), comment.c_str(), comment.size()) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-std::string ZipArchive::getComment(ZipFlags flags) const
-{
-	int length{};
-	auto text = zip_get_archive_comment(m_handle.get(), &length, flags);
-
-	if (text == nullptr)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return { text, static_cast<size_t>(length) };
-}
-
-ZipInt64 ZipArchive::find(const std::string &name, ZipFlags flags)
-{
-	auto index = zip_name_locate(m_handle.get(), name.c_str(), flags);
-
-	if (index < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return index;
-}
-
-ZipStat ZipArchive::stat(const std::string &name, ZipFlags flags) const
-{
-	ZipStat st;
-
-	if (zip_stat(m_handle.get(), name.c_str(), flags, &st) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return st;
-}
-
-ZipStat ZipArchive::stat(ZipUint64 index, ZipFlags flags) const
-{
-	ZipStat st;
-
-	if (zip_stat_index(m_handle.get(), index, flags, &st) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return st;
-}
-
-ZipInt64 ZipArchive::add(const ZipSource &source, const std::string &name, ZipFlags flags)
-{
-	auto src = source.source(m_handle.get());
-	auto ret = zip_file_add(m_handle.get(), name.c_str(), src, flags);
-
-	if (ret < 0) {
-		zip_source_free(src);
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-	}
-
-	return ret;
-}
-
-ZipInt64 ZipArchive::addDirectory(const std::string &directory, ZipFlags flags)
-{
-	auto ret = zip_dir_add(m_handle.get(), directory.c_str(), flags);
-
-	if (ret < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return ret;
-}
-
-void ZipArchive::replace(const ZipSource &source, ZipUint64 index, ZipFlags flags)
-{
-	auto src = source.source(m_handle.get());
-
-	if (zip_file_replace(m_handle.get(), index, src, flags) < 0) {
-		zip_source_free(src);
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-	}
-}
-
-ZipFile ZipArchive::open(const std::string &name, ZipFlags flags, const std::string &password)
-{
-	struct zip_file *file;
-
-	if (password.size() > 0)
-		file = zip_fopen_encrypted(m_handle.get(), name.c_str(), flags, password.c_str());
-	else
-		file = zip_fopen(m_handle.get(), name.c_str(), flags);
-
-	if (file == nullptr)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return file;
-}
-
-ZipFile ZipArchive::open(ZipUint64 index, ZipFlags flags, const std::string &password)
-{
-	struct zip_file *file;
-
-	if (password.size() > 0)
-		file = zip_fopen_index_encrypted(m_handle.get(), index, flags, password.c_str());
-	else
-		file = zip_fopen_index(m_handle.get(), index, flags);
-
-	if (file == nullptr)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return file;
-}
-
-void ZipArchive::rename(ZipUint64 index, const std::string &name, ZipFlags flags)
-{
-	if (zip_file_rename(m_handle.get(), index, name.c_str(), flags) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-void ZipArchive::setFileCompression(ZipUint64 index, ZipInt32 comp, ZipUint32 flags)
-{
-	if (zip_set_file_compression(m_handle.get(), index, comp, flags) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-void ZipArchive::remove(ZipUint64 index)
-{
-	if (zip_delete(m_handle.get(), index) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-ZipInt64 ZipArchive::numEntries(ZipFlags flags) const noexcept
-{
-	return zip_get_num_entries(m_handle.get(), flags);
-}
-
-void ZipArchive::unchange(ZipUint64 index)
-{
-	if (zip_unchange(m_handle.get(), index) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-void ZipArchive::unchangeAll()
-{
-	if (zip_unchange_all(m_handle.get()) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-void ZipArchive::unchangeArchive()
-{
-	if (zip_unchange_archive(m_handle.get()) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-void ZipArchive::setDefaultPassword(const std::string &password)
-{
-	auto cstr = (password.size() > 0) ? password.c_str() : nullptr;
-
-	if (zip_set_default_password(m_handle.get(), cstr) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-void ZipArchive::setFlag(ZipFlags flags, int value)
-{
-	if (zip_set_archive_flag(m_handle.get(), flags, value) < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-}
-
-int ZipArchive::getFlag(ZipFlags which, ZipFlags flags) const
-{
-	auto ret = zip_get_archive_flag(m_handle.get(), which, flags);
-
-	if (ret < 0)
-		throw std::runtime_error(zip_strerror(m_handle.get()));
-
-	return ret;
-}
--- a/C++/ZipArchive.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,727 +0,0 @@
-/*
- * ZipArchive.h -- wrapper around libzip
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _ZIP_ARCHIVE_H_
-#define _ZIP_ARCHIVE_H_
-
-#include <iterator>
-#include <memory>
-#include <string>
-
-#include <zip.h>
-
-using ZipStat = struct zip_stat;
-using ZipSourceCommand = enum zip_source_cmd;
-using ZipCallback = zip_source_callback;
-
-using ZipFlags	= zip_flags_t;
-using ZipInt8	= zip_int8_t;
-using ZipUint8	= zip_uint8_t;
-using ZipInt16	= zip_int16_t;
-using ZipUint16	= zip_uint16_t;
-using ZipInt32	= zip_int32_t;
-using ZipUint32	= zip_uint32_t;
-using ZipInt64	= zip_int64_t;
-using ZipUint64	= zip_uint64_t;
-
-/**
- * @class ZipSource
- * @brief Source for adding file
- */
-class ZipSource {
-public:
-	/**
-	 * Default constructor.
-	 */
-	ZipSource() = default;
-
-	/**
-	 * Virtual destructor.
-	 */
-	virtual ~ZipSource() = default;
-
-	/**
-	 * Create a zip_source structure. Must not be null, throw an exception
-	 * instead.
-	 *
-	 * @return a zip_source ready to be used
-	 * @throw std::runtime_error on errors
-	 * @post must not return null
-	 */
-	virtual struct zip_source *source(struct zip *zip) const = 0;
-};
-
-/**
- * @class ZipFile
- * @brief File for reading
- */
-class ZipFile {
-private:
-	std::unique_ptr<struct zip_file, int (*)(struct zip_file *)> m_handle;
-
-	ZipFile(const ZipFile &) = delete;
-	ZipFile &operator=(const ZipFile &) = delete;
-
-public:
-	/**
-	 * Create a ZipFile with a zip_file structure.
-	 *
-	 * @param file the file ready to be used
-	 */
-	inline ZipFile(struct zip_file *file)
-		: m_handle(file, zip_fclose)
-	{
-	}
-
-	/**
-	 * Move constructor defaulted.
-	 *
-	 * @param other the other ZipFile
-	 */
-	ZipFile(ZipFile &&other) noexcept = default;
-
-	/**
-	 * Move operator defaulted.
-	 *
-	 * @param other the other ZipFile
-	 * @return *this
-	 */
-	ZipFile &operator=(ZipFile &&) noexcept = default;
-
-	/**
-	 * Read some data.
-	 *
-	 * @param data the destination buffer
-	 * @param length the length
-	 * @return the number of bytes written or -1 on failure
-	 */
-	inline int read(void *data, ZipUint64 length) noexcept
-	{
-		return zip_fread(m_handle.get(), data, length);
-	}
-
-	/**
-	 * Read some data to a fixed size array.
-	 *
-	 * @param data the array
-	 * @return the number of bytes written or -1 on failure
-	 */
-	template <size_t Size>
-	inline int read(char (&data)[Size]) noexcept
-	{
-		return read(data, Size);
-	}
-
-	/**
-	 * Optimized function for reading all characters with only one allocation.
-	 * Ideal for combining with ZipArchive::stat.
-	 *
-	 * @param length the length of the file
-	 * @return the whole string
-	 * @see ZipArchive::stat
-	 */
-	std::string read(unsigned length)
-	{
-		std::string result;
-
-		result.resize(length);
-		auto count = read(&result[0], length);
-
-		if (count < 0)
-			return "";
-
-		result.resize(count);
-
-		return result;
-	}
-};
-
-namespace source {
-
-/**
- * @class Buffer
- * @brief Create a source from a buffer
- */
-class Buffer : public ZipSource {
-private:
-	std::string m_data;
-
-public:
-	/**
-	 * Buffer constructor. Moves the data.
-	 *
-	 * @param data the data
-	 */
-	Buffer(std::string data);
-
-	/**
-	 * @copydoc ZipSource::source
-	 */
-	struct zip_source *source(struct zip *archive) const override;
-};
-
-/**
- * @class File
- * @brief Create a source from a file on the disk
- */
-class File : public ZipSource {
-private:
-	std::string m_path;
-	ZipUint64 m_start;
-	ZipInt64 m_length;
-
-public:
-	/**
-	 * File constructor.
-	 *
-	 * @param path the path to the file
-	 * @param start the beginning in the file
-	 * @param length the maximum length
-	 */
-	File(std::string path, ZipUint64 start = 0, ZipInt64 length = -1);
-
-	/**
-	 * @copydoc ZipSource::source
-	 */
-	struct zip_source *source(struct zip *archive) const override;
-};
-
-} // !source
-
-/**
- * @class ZipStatPtr
- * @brief Wrapper for ZipStat as pointer
- */
-class ZipStatPtr {
-private:
-	ZipStat &m_stat;
-
-public:
-	/**
-	 * Constructor.
-	 *
-	 * @param stat the file stat
-	 */
-	inline ZipStatPtr(ZipStat stat) noexcept
-		: m_stat(stat)
-	{
-	}
-
-	/**
-	 * Get the reference.
-	 *
-	 * @return the reference
-	 */
-	inline ZipStat &operator*() const noexcept
-	{
-		return m_stat;
-	}
-
-	/**
-	 * Access the object.
-	 *
-	 * @return the pointer
-	 */
-	inline ZipStat *operator->() const noexcept
-	{
-		return &m_stat;
-	}
-};
-
-/**
- * @class ZipArchive
- * @brief Safe wrapper on the struct zip structure
- */
-class ZipArchive {
-private:
-	using Handle = std::unique_ptr<struct zip, int (*)(struct zip *)>;
-
-	Handle m_handle;
-
-	ZipArchive(const ZipArchive &) = delete;
-	ZipArchive &operator=(const ZipArchive &) = delete;
-
-public:
-	using value_type = ZipStat;
-	using reference = ZipStat;
-	using const_refernce = ZipStat;
-	using pointer = ZipStatPtr;
-	using size_type = unsigned;
-
-	/**
-	 * @class iterator
-	 * @brief Iterator
-	 */
-	class iterator : public std::iterator<std::random_access_iterator_tag, ZipArchive> {
-	private:
-		ZipArchive &m_archive;
-		ZipUint64 m_index;
-
-	public:
-		explicit inline iterator(ZipArchive &archive, ZipUint64 index = 0) noexcept
-			: m_archive(archive)
-			, m_index(index)
-		{
-		}
-
-		inline ZipStat operator*() const
-		{
-			return m_archive.stat(m_index);
-		}
-
-		inline ZipStatPtr operator->() const
-		{
-			return ZipStatPtr(m_archive.stat(m_index));
-		}
-
-		inline iterator &operator++() noexcept
-		{
-			++ m_index;
-
-			return *this;
-		}
-
-		inline iterator operator++(int) noexcept
-		{
-			iterator save = *this;
-
-			++ m_index;
-
-			return save;
-		}
-
-		inline iterator &operator--() noexcept
-		{
-			-- m_index;
-
-			return *this;
-		}
-
-		inline iterator operator--(int) noexcept
-		{
-			iterator save = *this;
-
-			-- m_index;
-
-			return save;
-		}
-
-		inline iterator operator+(int inc) const noexcept
-		{
-			return iterator(m_archive, m_index + inc);
-		}
-
-		inline iterator operator-(int dec) const noexcept
-		{
-			return iterator(m_archive, m_index - dec);
-		}
-
-		inline bool operator==(const iterator &other) const noexcept
-		{
-			return m_index == other.m_index;
-		}
-
-		inline bool operator!=(const iterator &other) const noexcept
-		{
-			return m_index != other.m_index;
-		}
-
-		inline ZipStat operator[](int index) const
-		{
-			return m_archive.stat(index);
-		}
-	};
-
-	/**
-	 * @class const_iterator
-	 * @brief Const iterator
-	 */
-	class const_iterator : public std::iterator<std::random_access_iterator_tag, ZipArchive> {
-	private:
-		const ZipArchive &m_archive;
-		ZipUint64 m_index;
-
-	public:
-		explicit inline const_iterator(const ZipArchive &archive, ZipUint64 index = 0) noexcept
-			: m_archive(archive)
-			, m_index(index)
-		{
-		}
-
-		inline ZipStat operator*() const
-		{
-			return m_archive.stat(m_index);
-		}
-
-		inline ZipStatPtr operator->() const
-		{
-			return ZipStatPtr(m_archive.stat(m_index));
-		}
-
-		inline const_iterator &operator++() noexcept
-		{
-			++ m_index;
-
-			return *this;
-		}
-
-		inline const_iterator operator++(int) noexcept
-		{
-			const_iterator save = *this;
-
-			++ m_index;
-
-			return save;
-		}
-
-		inline const_iterator &operator--() noexcept
-		{
-			-- m_index;
-
-			return *this;
-		}
-
-		inline const_iterator operator--(int) noexcept
-		{
-			const_iterator save = *this;
-
-			-- m_index;
-
-			return save;
-		}
-
-		inline const_iterator operator+(int inc) const noexcept
-		{
-			return const_iterator(m_archive, m_index + inc);
-		}
-
-		inline const_iterator operator-(int dec) const noexcept
-		{
-			return const_iterator(m_archive, m_index - dec);
-		}
-
-		inline bool operator==(const const_iterator &other) const noexcept
-		{
-			return m_index == other.m_index;
-		}
-
-		inline bool operator!=(const const_iterator &other) const noexcept
-		{
-			return m_index != other.m_index;
-		}
-
-		inline ZipStat operator[](int index) const
-		{
-			return m_archive.stat(index);
-		}
-	};
-
-public:
-	/**
-	 * Open an archive on the disk.
-	 *
-	 * @param path the path
-	 * @param flags the optional flags
-	 * @throw std::runtime_error on errors
-	 */
-	ZipArchive(const std::string &path, ZipFlags flags = 0);
-
-	/**
-	 * Move constructor defaulted.
-	 *
-	 * @param other the other ZipArchive
-	 */
-	ZipArchive(ZipArchive &&other) noexcept = default;
-
-	/**
-	 * Move operator defaulted.
-	 *
-	 * @param other the other ZipArchive
-	 * @return *this
-	 */
-	ZipArchive &operator=(ZipArchive &&other) noexcept = default;
-
-	/**
-	 * Get an iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline iterator begin() noexcept
-	{
-		return iterator(*this);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator begin() const noexcept
-	{
-		return const_iterator(*this);
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator cbegin() const noexcept
-	{
-		return const_iterator(*this);
-	}
-
-	/**
-	 * Get an iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline iterator end() noexcept
-	{
-		return iterator(*this, numEntries());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator end() const noexcept
-	{
-		return const_iterator(*this, numEntries());
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline const_iterator cend() const noexcept
-	{
-		return const_iterator(*this, numEntries());
-	}
-
-	/**
-	 * Set a comment on a file.
-	 *
-	 * @param index the file index in the archive
-	 * @param text the text or empty to remove the comment
-	 * @param flags the optional flags
-	 * @throw std::runtime_error on errors
-	 */
-	void setFileComment(ZipUint64 index, const std::string &text = "", ZipFlags flags = 0);
-
-	/**
-	 * Get a comment from a file.
-	 *
-	 * @param index the file index in the archive
-	 * @param flags the optional flags
-	 * @return the comment
-	 * @throw std::runtime_error on errors
-	 */
-	std::string getFileComment(ZipUint64 index, ZipFlags flags = 0) const;
-
-	/**
-	 * Set the archive comment.
-	 *
-	 * @param comment the comment
-	 * @throw std::runtime_error on errors
-	 */
-	void setComment(const std::string &comment);
-
-	/**
-	 * Get the archive comment.
-	 *
-	 * @param flags the optional flags
-	 * @return the comment
-	 * @throw std::runtime_error on errors
-	 */
-	std::string getComment(ZipFlags flags = 0) const;
-
-	/**
-	 * Locate a file on the archive.
-	 *
-	 * @param name the name
-	 * @param flags the optional flags
-	 * @return the index
-	 * @throw std::runtime_error on errors
-	 */
-	ZipInt64 find(const std::string &name, ZipFlags flags = 0);
-
-	/**
-	 * Get information about a file.
-	 *
-	 * @param name the name
-	 * @param flags the optional flags
-	 * @return the structure
-	 * @throw std::runtime_error on errors
-	 */
-	ZipStat stat(const std::string &name, ZipFlags flags = 0) const;
-
-	/**
-	 * Get information about a file. Overloaded function.
-	 *
-	 * @param index the file index in the archive
-	 * @param flags the optional flags
-	 * @return the structure
-	 * @throw std::runtime_error on errors
-	 */
-	ZipStat stat(ZipUint64 index, ZipFlags flags = 0) const;
-
-	/**
-	 * Add a file to the archive.
-	 *
-	 * @param source the source
-	 * @param name the name entry in the archive
-	 * @param flags the optional flags
-	 * @return the new index in the archive
-	 * @throw std::runtime_error on errors
-	 * @see source::File
-	 * @see source::Buffer
-	 */
-	ZipInt64 add(const ZipSource &source, const std::string &name, ZipFlags flags = 0);
-
-	/**
-	 * Add a directory to the archive. Not a directory from the disk.
-	 *
-	 * @param directory the directory name
-	 * @param flags the optional flags
-	 * @return the new index in the archive
-	 * @throw std::runtime_error on errors
-	 */
-	ZipInt64 addDirectory(const std::string &directory, ZipFlags flags = 0);
-
-	/**
-	 * Replace an existing file in the archive.
-	 *
-	 * @param source the source
-	 * @param index the file index in the archiev
-	 * @param flags the optional flags
-	 * @throw std::runtime_error on errors
-	 */
-	void replace(const ZipSource &source, ZipUint64 index, ZipFlags flags = 0);
-
-	/**
-	 * Open a file in the archive.
-	 *
-	 * @param name the name
-	 * @param flags the optional flags
-	 * @param password the optional password
-	 * @return the opened file
-	 * @throw std::runtime_error on errors
-	 */
-	ZipFile open(const std::string &name, ZipFlags flags = 0, const std::string &password = "");
-
-	/**
-	 * Open a file in the archive. Overloaded function.
-	 *
-	 * @param index the file index in the archive
-	 * @param flags the optional flags
-	 * @param password the optional password
-	 * @return the opened file
-	 * @throw std::runtime_error on errors
-	 */
-	ZipFile open(ZipUint64 index, ZipFlags flags = 0, const std::string &password = "");
-
-	/**
-	 * Rename an existing entry in the archive.
-	 *
-	 * @param index the file index in the archive
-	 * @param name the new name
-	 * @param flags the optional flags
-	 * @throw std::runtime_error on errors
-	 */
-	void rename(ZipUint64 index, const std::string &name, ZipFlags flags = 0);
-
-	/**
-	 * Set file compression.
-	 *
-	 * @param index the file index in the archive
-	 * @param comp the compression
-	 * @param flags the optional flags
-	 * @throw std::runtime_error on errors
-	 */
-	void setFileCompression(ZipUint64 index, ZipInt32 comp, ZipUint32 flags = 0);
-
-	/**
-	 * Delete a file from the archive.
-	 *
-	 * @param index the file index in the archive
-	 * @throw std::runtime_error on errors
-	 */
-	void remove(ZipUint64 index);
-
-	/**
-	 * Get the number of entries in the archive.
-	 *
-	 * @param flags the optional flags
-	 * @return the number of entries
-	 */
-	ZipInt64 numEntries(ZipFlags flags = 0) const noexcept;
-
-	/**
-	 * Revert changes on the file.
-	 *
-	 * @param index the index
-	 * @throw std::runtime_error on errors
-	 */
-	void unchange(ZipUint64 index);
-
-	/**
-	 * Revert all changes.
-	 *
-	 * @throw std::runtime_error on errors
-	 */
-	void unchangeAll();
-
-	/**
-	 * Revert changes to archive.
-	 *
-	 * @throw std::runtime_error on errors
-	 */
-	void unchangeArchive();
-
-	/**
-	 * Set the defaut password.
-	 *
-	 * @param password the password or empty to unset it
-	 * @throw std::runtime_error on errors
-	 */
-	void setDefaultPassword(const std::string &password = "");
-
-	/**
-	 * Set an archive flag.
-	 *
-	 * @param flag the flag to set
-	 * @param value the value
-	 * @throw std::runtime_error on errors
-	 */
-	void setFlag(ZipFlags flag, int value);
-
-	/**
-	 * Get an archive flag.
-	 *
-	 * @param which which flag
-	 * @param flags the optional flags
-	 * @return the value
-	 * @throw std::runtime_error on errors
-	 */
-	int getFlag(ZipFlags which, ZipFlags flags = 0) const;
-};
-
-#endif // !_ZIP_ARCHIVE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/Home.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,69 @@
+# DynLib
+
+This class provides routines to load shared libraries in a portable manner.
+
+## Operating system support
+
+| System  | Support  | Remarks                             |
+|---------|----------|-------------------------------------|
+| Linux   | Complete | Linker needs -ldl linker flags      |
+| FreeBSD | Complete |                                     |
+| Windows | Complete | Immediately policy is not available |
+
+## API Reference
+
+### Macros constants
+
+- [DYNLIB_EXPORT](macro/DYNLIB_EXPORT.md)
+
+### Classes
+
+- [DynLib](class/Dynlib.md)
+
+## Tutorial
+
+This is the library code to be compiled as a shared module.
+
+**Library.cpp**
+
+````cpp
+#include <iostream>
+#include <string>
+
+#include "DynLib.h"
+
+extern "C" {
+
+DYNLIB_EXPORT void a_sayHello(const std::string &name)
+{
+	std::cout << "Hello " << name << "!" << std::endl;
+}
+
+}
+````
+
+And this is the code that load the shared module.
+
+**Main.cpp**
+
+````cpp
+#include <iostream>
+
+#include "DynLib.h"
+
+using HelloFunc = void (*)(const std::string &);
+
+int main(void)
+{
+	try {
+		DynLib library("./liba.so");
+
+		HelloFunc hello = library.sym<HelloFunc>("a_sayHello");
+		hello("Test");
+	} catch (const std::exception &error) {
+		std::cerr << error.what() << std::endl;
+	}
+
+	return 0;
+}
+````
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/class/Dynlib.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,19 @@
+# DynLib
+
+Dynamic loading library.
+
+## Class
+
+````cpp
+class DynLib;
+````
+
+### Public member functions
+
+- [(Constructor)](Dynlib/Constructor.md)
+- [(Destructor)](Dynlib/Destructor.md)
+- [sym (template)](Dynlib/sym.md)
+
+### Public member types
+
+- [Policy](Dynlib/Policy.md)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/class/Dynlib/Constructor.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,44 @@
+# Constructor
+
+Construct an empty DynLib.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+DynLib();
+````
+
+# Constructor
+
+Open the library at the specified path.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+DynLib(const std::string &path, Policy policy = Immediately);
+````
+
+### ARGUMENTS
+
+- path, the path. Must be absolute
+- policy, the policy (see [Policy](Policy.md))
+
+### THROWS
+
+- [std::runtime_error](http://en.cppreference.com/w/cpp/error/runtime_error) on failures.
+
+# Constructor (copy)
+
+The copy constructor is disabled.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+DynLib(const DynLib &) = delete;
+````
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/class/Dynlib/Destructor.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,11 @@
+# Destructor
+
+The destructor close any handle and further calls to loaded symbols is undefined behaviour.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+~DynLib();
+````
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/class/Dynlib/Policy.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,19 @@
+# Policy
+
+The policy set the opening settings. Not all policies are available.
+
+## Enum
+
+### SYNOPSIS
+
+````cpp
+enum Policy {
+	Immediately,
+	Lazy
+};
+````
+
+### VALUES
+
+- Immediately, load all symbols immediately
+- Lazy, load symbols when needed
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/class/Dynlib/sym.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,33 @@
+# sym (template)
+
+Retrieves a symbol from the shared library.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+template <typename T>
+T sym(const std::string &name)
+````
+
+### ARGUMENTS
+
+- name, the symbol name
+
+### RETURNS
+
+The symbol cast to the template type.
+
+### THROWS
+
+- [std::runtime_error](http://en.cppreference.com/w/cpp/error/runtime_error) on errors
+- [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range) when symbol is not found
+
+### NOTES
+
+On some systems, if you forgot to add [DYNLIB_EXPORT](../../macro/DYNLIB_EXPORT.md) attribute to the function, it won't find the symbol.
+
+### REMARKS
+
+Be sure that the DynLib object is not destroyed when you use the symbol, otherwise it is undefined behaviour.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Dynlib/macro/DYNLIB_EXPORT.md	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,23 @@
+# DYNLIB_EXPORT
+
+This macro is needed on some systems as a function attribute to export the symbol. If you omit it, some symbols will not be available.
+
+## Macro
+
+### SYNOPSIS
+
+````cpp
+#define DYNLIB_EXPORT /* implementation-defined */
+````
+
+### EXAMPLE
+
+````cppp
+extern "C" {
+
+DYNLIB_EXPORT int myfunction(void) {
+    return 0;
+}
+
+}
+````
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Base64/Base64.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * Base64.cpp -- base64 encoding and decoding
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iterator>
+#include <sstream>
+
+#include "Base64.h"
+
+char Base64::lookup(int value) noexcept
+{
+	static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+	return table[value];
+}
+
+int Base64::rlookup(char ch)
+{
+	if (ch == '+')
+		return 62;
+	if (ch == '/')
+		return 63;
+
+	if (ch >= '0' && ch <= '9')
+		return ch + 4;
+	if (ch >= 'A' && ch <= 'Z')
+		return ch - 65;
+	if (ch >= 'a' && ch <= 'z')
+		return ch - 71;
+
+	throw std::invalid_argument("not a valid base64 string");
+}
+
+std::string Base64::encode(const std::string &input)
+{
+	std::string result;
+	std::istringstream iss(input, std::istringstream::in);
+
+	encode(std::istreambuf_iterator<char>(iss), std::istreambuf_iterator<char>(), std::back_inserter(result));
+
+	return result;
+}
+
+std::string Base64::decode(const std::string &input)
+{
+	std::string result;
+	std::istringstream iss(input, std::istringstream::in);
+
+	decode(std::istreambuf_iterator<char>(iss), std::istreambuf_iterator<char>(), std::back_inserter(result));
+
+	return result;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Base64/Base64.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,134 @@
+/*
+ * Base64.h -- base64 encoding and decoding
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BASE_64_H_
+#define _BASE_64_H_
+
+/**
+ * @file Base64.h
+ * @brief Base64 encoding and decoding
+ */
+
+#include <stdexcept>
+#include <string>
+
+/**
+ * @class Base64
+ * @brief Encode and decode Base64 data
+ */
+class Base64 {
+public:
+	/**
+	 * Get the base 64 character from the 6-bits value.
+	 *
+	 * @param value the value
+	 */
+	static char lookup(int value) noexcept;
+
+	/**
+	 * Get the integer value from the base 64 character.
+	 *
+	 * @param ch the base64 character
+	 */
+	static int rlookup(char ch);
+
+	/**
+	 * Encode the input to the output. Requirements:
+	 *	InputIt	must be InputIterator
+	 *	OutputIt must be OutputIterator
+	 *
+	 * @param input the beginning
+	 * @param end the end of the data
+	 * @param output the output destination
+	 * @return output
+	 */
+	template <typename InputIt, typename OutputIt>
+	static OutputIt encode(InputIt input, InputIt end, OutputIt output)
+	{
+		while (input != end) {
+			char inputbuf[3] = { 0, 0, 0 };
+			int count;
+
+			for (count = 0; count < 3 && input != end; ++count)
+				inputbuf[count] = *input++;
+
+			*output++ = lookup(inputbuf[0] >> 2 & 0x3f);
+			*output++ = lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f));
+			*output++ = (count < 2) ? '=' : lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03));
+			*output++ = (count < 3) ? '=' : lookup(inputbuf[2] & 0x3f);
+		}
+
+		return output;
+	}
+
+	/**
+	 * Decode the input to the output. Requirements:
+	 *	InputIt must be InputIterator
+	 *	OutputIt must be OutputIterator
+	 *
+	 * @param input the beginning
+	 * @param end the end of the data
+	 * @param output the output destination
+	 * @return output
+	 * @throw std::invalid_argument on bad base64 string
+	 */
+	template <typename InputIt, typename OutputIt>
+	static OutputIt decode(InputIt input, InputIt end, OutputIt output)
+	{
+		while (input != end) {
+			char inputbuf[4] = { 0, 0, 0, 0 };
+			int count;
+
+			for (count = 0; count < 4 && input != end; ++count) {
+				inputbuf[count] = (*input == '=') ? '=' : rlookup(*input);
+				input++;
+			}
+
+			if (count != 4)
+				throw std::invalid_argument("truncated string");
+
+			*output++ = (inputbuf[0] << 2 & 0xfc) | (inputbuf[1] >> 4 & 0x03);
+
+			if (inputbuf[2] != '=')
+				*output++ = (inputbuf[1] << 4 & 0xf0) | (inputbuf[2] >> 2 & 0x0f);
+			if (inputbuf[3] != '=')
+				*output++ = (inputbuf[2] << 6 & 0xc0) | (inputbuf[3] & 0x3f);
+		}
+
+		return output;
+	}
+
+	/**
+	 * Encode a string.
+	 *
+	 * @param input the input string
+	 * @return the base64 formatted string
+	 */
+	static std::string encode(const std::string &input);
+
+	/**
+	 * Decode a string.
+	 *
+	 * @param input the base64 formatted string
+	 * @return the original string
+	 * @throw std::invalid_argument on bad base64 string
+	 */
+	static std::string decode(const std::string &input);
+};
+
+#endif // !_BASE_64_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Converter/Converter.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,92 @@
+/*
+ * Converter.cpp -- iconv based converter
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cerrno>
+#include <cstring>
+#include <string>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <stdexcept>
+#include <vector>
+
+#include <iconv.h>
+
+#include "Converter.h"
+
+struct Deleter {
+	void operator()(iconv_t desc)
+	{
+		iconv_close(desc);
+	}
+};
+
+using Iconv = std::unique_ptr<std::remove_pointer<iconv_t>::type, Deleter>;
+
+std::string Converter::convert(const char *from,
+			       const char *to,
+			       const std::string &input)
+{
+	// No conversion if from and to are identical
+	if (std::strcmp(from, to) == 0)
+		return input;
+
+	// Try to open the conversion descriptor
+	auto cd = iconv_open(to, from);
+
+	if (cd == (iconv_t)-1)
+		throw std::invalid_argument(std::strerror(errno));
+
+	Iconv cv(cd);
+	std::size_t insize(input.size());
+	std::size_t outsize(insize);
+	std::vector<char> result(insize + 1);
+
+	auto *b = &input[0];
+	auto *p = &result[0];
+
+	while (insize > 0) {
+		/* Convert */
+		auto r = iconv(cv.get(), &b, &insize, &p, &outsize);
+
+		if (r == (size_t)-1) {
+			switch (errno) {
+			case EBADF:
+			case EILSEQ:
+			case EINVAL:
+				throw std::invalid_argument(std::strerror(errno));
+			case E2BIG:
+				/*
+				 * Here, we need to reallocate more data because the output
+				 * string may need more space.
+				 *
+				 * We use 16 as an optimistic value.
+				 */
+
+				result.reserve(result.size() + 16 + 1);
+				p = &result[result.size()];
+				outsize += 16;
+			default:
+				break;
+			}
+		}
+
+	}
+
+	return std::string(&result[0], (p - &result[0]));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Converter/Converter.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * Converter.h -- iconv based converter
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _CONVERTER_H_
+#define _CONVERTER_H_
+
+/**
+ * @file Converter.h
+ * @brief Converter using libiconv
+ */
+
+#include <string>
+
+/**
+ * @class Converter
+ * @brief Convert string between different encodings
+ */
+class Converter {
+public:
+	/**
+	 * Convert the string into a different encoding.
+	 *
+	 * @param from the from encoding
+	 * @param to the destination encoding
+	 * @param input the string to convert
+	 * @return the converted string
+	 * @throw std::invalid_argument on invalid sequence
+	 */
+	static std::string convert(const char *from,
+				   const char *to,
+				   const std::string &input);
+};
+
+#endif // !_CONVERTER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Date/Date.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,59 @@
+/*
+ * Date.cpp -- date and time manipulation
+ *
+ * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "Date.h"
+
+Date::Date()
+{
+	m_timestamp = time(NULL);
+}
+
+Date::Date(time_t timestamp)
+{
+	m_timestamp = timestamp;
+}
+
+Date::~Date()
+{
+}
+
+time_t Date::getTimestamp() const
+{
+	return m_timestamp;
+}
+
+std::string Date::format(const std::string &format)
+{
+	char buffer[512];
+	struct tm *tm;
+
+	tm = localtime(&m_timestamp);
+	strftime(buffer, sizeof (buffer), format.c_str(), tm);
+
+	return std::string(buffer);
+}
+
+bool operator==(const Date &d1, const Date &d2)
+{
+	return d1.getTimestamp() == d2.getTimestamp();
+}
+
+bool operator<=(const Date &d1, const Date &d2)
+{
+	return d1.getTimestamp() <= d2.getTimestamp();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Date/Date.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,55 @@
+/*
+ * Date.h -- date and time manipulation
+ *
+ * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DATE_H_
+#define _DATE_H_
+
+#include <cstdint>
+#include <ctime>
+#include <string>
+
+struct Date
+{
+	time_t m_timestamp;		//! time epoch
+
+	Date();
+	Date(time_t timestamp);
+	~Date();
+
+	/**
+	 * Get the timestamp.
+	 *
+	 * @return the timestamp
+	 */
+	time_t getTimestamp() const;
+
+	/**
+	 * Format the current that in the specified format,
+	 * see strftime(3) for patterns.
+	 *
+	 * @param format the format
+	 * @return the date formated
+	 */
+	std::string format(const std::string &format);
+};
+
+bool operator==(const Date &, const Date &);
+
+bool operator<=(const Date &, const Date &);
+
+#endif // !_DATE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Directory/Directory.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,189 @@
+/*
+ * Directory.cpp -- open and read directories
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sstream>
+#include <stdexcept>
+
+#include "Directory.h"
+
+#if defined(_WIN32)
+#  include <Windows.h>
+#else
+#  include <cstring>
+#  include <cerrno>
+
+#  include <sys/types.h>
+#  include <dirent.h>
+#endif
+
+#if defined(_WIN32)
+
+namespace {
+
+std::string systemError()
+{
+	LPSTR error = nullptr;
+	std::string errmsg = "Unknown error";
+
+	FormatMessageA(
+		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL,
+		GetLastError(),
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		(LPSTR)&error, 0, NULL);
+
+	if (error) {
+		errmsg = std::string(error);
+		LocalFree(error);
+	}
+
+	return errmsg;
+}
+
+}
+
+void Directory::systemLoad(const std::string &path, int flags)
+{
+	std::ostringstream oss;
+	HANDLE handle;
+	WIN32_FIND_DATA fdata;
+
+	oss << path << "\\*";
+	handle = FindFirstFile(oss.str().c_str(), &fdata);
+
+	if (handle == nullptr)
+		throw std::runtime_error(systemError());
+
+	do {
+		Entry entry;
+
+		entry.name = fdata.cFileName;
+		if ((flags & Directory::NotDot) && entry.name == ".")
+			continue;
+		if ((flags & Directory::NotDotDot) && entry.name == "..")
+			continue;
+
+		switch (fdata.dwFileAttributes) {
+		case FILE_ATTRIBUTE_DIRECTORY:
+			entry.type = Dir;
+			break;
+		case FILE_ATTRIBUTE_NORMAL:
+			entry.type = File;
+			break;
+		case FILE_ATTRIBUTE_REPARSE_POINT:
+			entry.type = Link;
+			break;
+		default:
+			break;
+		}
+
+		m_list.push_back(entry);
+	} while (FindNextFile(handle, &fdata) != 0);
+
+	FindClose(handle);
+}
+
+#else
+
+void Directory::systemLoad(const std::string &path, int flags)
+{
+	DIR *dp;
+	struct dirent *ent;
+
+	if ((dp = opendir(path.c_str())) == nullptr)
+		throw std::runtime_error(strerror(errno));
+
+	while ((ent = readdir(dp)) != nullptr) {
+		Entry entry;
+
+		entry.name = ent->d_name;
+		if ((flags & Directory::NotDot) && entry.name == ".")
+			continue;
+		if ((flags & Directory::NotDotDot) && entry.name == "..")
+			continue;
+
+		switch (ent->d_type) {
+		case DT_DIR:
+			entry.type = Dir;
+			break;
+		case DT_REG:
+			entry.type = File;
+			break;
+		case DT_LNK:
+			entry.type = Link;
+			break;
+		default:
+			break;
+		}
+
+		m_list.push_back(entry);
+	}
+
+	closedir(dp);
+}
+
+#endif
+
+Directory::Entry::Entry()
+	: type(Unknown)
+{
+}
+
+bool operator==(const Directory::Entry &e1, const Directory::Entry &e2)
+{
+	return e1.name == e2.name && e1.type == e2.type;
+}
+
+Directory::Directory()
+{
+}
+
+Directory::Directory(const std::string &path, int flags)
+{
+	systemLoad(path, flags);
+}
+
+Directory::List::iterator Directory::begin()
+{
+	return m_list.begin();
+}
+
+Directory::List::const_iterator Directory::cbegin() const
+{
+	return m_list.cbegin();
+}
+
+Directory::List::iterator Directory::end()
+{
+	return m_list.end();
+}
+
+Directory::List::const_iterator Directory::cend() const
+{
+	return m_list.cend();
+}
+
+int Directory::count() const
+{
+	return m_list.size();
+}
+
+bool operator==(const Directory &d1, const Directory &d2)
+{
+	return d1.m_list == d2.m_list;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Directory/Directory.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,131 @@
+/*
+ * Directory.h -- open and read directories
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DIRECTORY_H_
+#define _DIRECTORY_H_
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+/**
+ * @class Directory
+ * @brief class to manipulate directories
+ *
+ * This class allow the user to iterate directories in a for range based
+ * loop using iterators.
+ */
+class Directory {
+public:
+	/**
+	 * @enum Flags
+	 * @brief optional flags to read directories
+	 */
+	enum Flags {
+		NotDot		= (1 << 0),
+		NotDotDot	= (1 << 1)
+	};
+
+	/**
+	 * @enum Type
+	 * @brief Describe the type of an entry
+	 */
+	enum Type {
+		Unknown		= 0,
+		File,
+		Dir,
+		Link
+	};
+
+	/**
+	 * @struct Entry
+	 * @brief entry in the directory list
+	 */
+	struct Entry {
+		std::string	name;		//! name of entry (base name)
+		Type		type;		//! type of file
+
+		Entry();
+
+		friend bool operator==(const Entry &e1, const Entry &e2);
+	};
+
+	using List = std::vector<Entry>;
+
+	// C++ Container compatibility
+	using value_type	= List::value_type;
+	using iterator		= List::iterator;
+	using const_iterator	= List::const_iterator;
+
+private:
+	List m_list;
+
+	void systemLoad(const std::string &path, int flags);
+
+public:
+	/**
+	 * Default constructor, does nothing.
+	 */
+	Directory();
+
+	/**
+	 * Open a directory and read all its content.
+	 * @param path the path
+	 * @param flags the optional flags
+	 */
+	Directory(const std::string &path, int flags = 0);
+
+	/**
+	 * Return an iterator the beginning.
+	 *
+	 * @return the iterator
+	 */
+	List::iterator begin();
+
+	/**
+	 * Return a const iterator the beginning.
+	 *
+	 * @return the iterator
+	 */
+	List::const_iterator cbegin() const;
+
+	/**
+	 * Return an iterator to past the end.
+	 *
+	 * @return the iterator
+	 */
+	List::iterator end();
+
+	/**
+	 * Return a const iterator to past the end.
+	 *
+	 * @return the iterator
+	 */
+	List::const_iterator cend() const;
+
+	/**
+	 * Get the number of entries in the directory.
+	 *
+	 * @return the number
+	 */
+	int count() const;
+
+	friend bool operator==(const Directory &d1, const Directory &d2);
+};
+
+#endif // !_DIRECTORY_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Driver/Driver.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,155 @@
+/*
+ * Driver.cpp -- generic SQL driver access
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdexcept>
+#include <sstream>
+
+#include "Driver.h"
+
+/* ---------------------------------------------------------
+ * DriverQuery class
+ * ---------------------------------------------------------*/
+
+DriverQuery::DriverQuery(Ptr impl)
+	: m_impl(impl)
+{
+}
+
+void DriverQuery::assertRequest(int row, const std::string &column, DriverColumn wanted)
+{
+	std::ostringstream oss;
+
+	// Out of bounds?
+	if (row < 0 || row >= countRows()) {
+		oss << "Invalid row index " << row;
+		oss << ", expected [0.." << countRows() << "]";
+
+		throw std::runtime_error(oss.str());
+	}
+
+	// Not found or bad column?
+	if (type(column) != wanted) {
+		oss << "Invalid or not found column `" << column << "'";
+
+		throw std::runtime_error(oss.str());
+	}
+}
+
+DriverQuery::~DriverQuery()
+{
+}
+
+DriverColumn DriverQuery::type(const std::string &column) const
+{
+	return m_impl->type(column);
+}
+
+int DriverQuery::countRows()
+{
+	return m_impl->countRows();
+}
+
+int DriverQuery::countColumns()
+{
+	return m_impl->countColumns();
+}
+
+bool DriverQuery::isNull(int row, const std::string &column)
+{
+	return m_impl->isNull(row, column);
+}
+
+void DriverQuery::dump()
+{
+	m_impl->dump();
+}
+
+/* --------------------------------------------------------
+ * DriverRequest class
+ * -------------------------------------------------------- */
+
+DriverRequest::DriverRequest(Ptr impl, const std::string &command)
+	: m_pos(0)
+	, m_params(0)
+	, m_command(command)
+	, m_impl(impl)
+{
+	int i = -1;
+
+	while ((i = command.find('#', i + 1)) != std::string::npos)
+		++ m_params;
+}
+
+DriverRequest::~DriverRequest()
+{
+}
+
+void DriverRequest::assertCorrect()
+{
+	if (m_params <= 0)
+		throw std::runtime_error("no more arguments to set");
+}
+
+void DriverRequest::setValue(const std::string &value)
+{
+	assertCorrect();
+
+	m_pos = m_command.find('#', m_pos);
+	m_command.replace(m_pos, 1, value);
+	m_pos += value.length();
+	m_params --;
+}
+
+DriverRequest::operator std::string()
+{
+	return m_command;
+}
+
+/* --------------------------------------------------------
+ * Driver class
+ * -------------------------------------------------------- */
+
+void Driver::connect(const Params &params)
+{
+	m_impl->connect(params);
+}
+
+DriverRequest Driver::prepare(const std::string &command)
+{
+	return m_impl->prepare(command);
+}
+
+DriverQuery Driver::query(const std::string &sql)
+{
+	return m_impl->query(sql);
+}
+
+DriverQuery Driver::query(DriverRequest request)
+{
+	return query(static_cast<std::string>(request));
+}
+
+std::string Driver::description() const
+{
+	return m_impl->description();
+}
+
+std::string Driver::version() const
+{
+	return m_impl->version();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Driver/Driver.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,529 @@
+/*
+ * Driver.h -- generic SQL driver access
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DRIVER_H_
+#define _DRIVER_H_
+
+#include <ctime>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <type_traits>
+
+/**
+ * @enum DriverColumn
+ * @brief The column type request
+ *
+ * Used for the drivers.
+ */
+enum class DriverColumn {
+	Invalid,			//! not found
+	Boolean,			//! bool or 0 / 1
+	Date,				//! date see Common/Date.h
+	Double,				//! double
+	Integer,			//! 32 or 64 bit int
+	String,				//! varchar to std::string
+};
+
+template <typename T>
+struct DriverTypeInfo : std::false_type { };
+
+/**
+ * @class Query
+ * @brief Class for querying the database
+ *
+ * That class is returned when a SQL query succeed. It can retrieve the
+ * number of rows, columns and retrieve the results independantly from the
+ * driver.
+ *
+ * @see Driver::query
+ */
+class DriverQuery {
+public:
+	friend struct DriverTypeInfo<bool>;
+	friend struct DriverTypeInfo<time_t>;
+	friend struct DriverTypeInfo<double>;
+	friend struct DriverTypeInfo<int>;
+	friend struct DriverTypeInfo<std::string>;
+
+	class Impl {
+	public:
+		/**
+		 * Get a bool.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual bool getBoolean(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a Date.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual time_t getDate(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a double.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual double getDouble(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a integer.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual int getInt(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a string.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual std::string getString(int row, const std::string &column) = 0;
+
+		/**
+		 * Returns the type of a named column.
+		 *
+		 * @param column the column name
+		 * @return the type
+		 */
+		virtual DriverColumn type(const std::string &column) const = 0;
+
+		/**
+		 * Tells how many rows has been fetched.
+		 *
+		 * @return the number of rows
+		 */
+		virtual int countRows() = 0;
+
+		/**
+		 * Tells how many number of columns are present for each
+		 * row.
+		 *
+		 * @return the number of columns
+		 */
+		virtual int countColumns() = 0;
+
+		/**
+		 * Tells if the column is null or not.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return an true if null
+		 */
+		virtual bool isNull(int row, const std::string &column) = 0;
+
+		/**
+		 * Dump all rows and columns.
+		 */
+		virtual void dump() = 0;
+	};
+
+	using Ptr	= std::shared_ptr<Impl>;
+
+private:
+	/**
+	 * Check if the request is valid and throws an exception
+	 * on error.
+	 *
+	 * @param row the row number
+	 * @param column the column name
+	 * @param type
+	 * @throw Error on error
+	 */
+	void assertRequest(int row, const std::string &column, DriverColumn type);
+
+protected:
+	Ptr		m_impl;
+
+public:
+	DriverQuery(Ptr impl);
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~DriverQuery();
+
+	/**
+	 * Get a variable from a row and column.
+	 *
+	 * Specialization available:
+	 *	- bool
+	 *	- Date
+	 *	- double
+	 *	- int
+	 *	- std::string
+	 *
+	 * @param row the row number (starts from 0)
+	 * @param column the the column name
+	 * @return the value
+	 * @throw Query::Error on error
+	 */
+	template <class T>
+	T get(int row, const std::string &column)
+	{
+		static_assert(DriverTypeInfo<T>::value, "unsupported type");
+
+		assertRequest(row, column, DriverTypeInfo<T>::type);
+	
+		return DriverTypeInfo<T>::get(*this, row, column);
+	}
+
+	/**
+	 * Returns the type of a named column.
+	 *
+	 * @param column the column name
+	 * @return the type
+	 */
+	DriverColumn type(const std::string &column) const;
+
+	/**
+	 * Tells how many rows has been fetched.
+	 *
+	 * @return the number of rows
+	 */
+	int countRows();
+
+	/**
+	 * Tells how many number of columns are present for each
+	 * row.
+	 *
+	 * @return the number of columns
+	 */
+	int countColumns();
+
+	/**
+	 * Tells if the column is null or not.
+	 *
+	 * @param row the row number
+	 * @param column the column
+	 * @return an true if null
+	 */
+	bool isNull(int row, const std::string &column);
+
+	/**
+	 * Dump all rows and columns.
+	 */
+	void dump();
+};
+
+/**
+ * @class Request
+ * @brief A secure helper for creating requests
+ *
+ * This helps creating class with SQL injection security and such.
+ */
+class DriverRequest {
+public:
+	friend struct DriverTypeInfo<bool>;
+	friend struct DriverTypeInfo<time_t>;
+	friend struct DriverTypeInfo<double>;
+	friend struct DriverTypeInfo<int>;
+	friend struct DriverTypeInfo<std::string>;
+
+	class Impl {
+	public:
+		/**
+		 * Bind a boolean.
+		 *
+		 * @param value the boolean
+		 * @return the string to use
+		 */
+		virtual std::string bindBoolean(bool value) = 0;
+
+		/**
+		 * Bind a date.
+		 *
+		 * @param value the date
+		 * @return the string to use
+		 */
+		virtual std::string bindDate(time_t value) = 0;
+
+		/**
+		 * Bind a double.
+		 *
+		 * @param value the double
+		 * @return the string to use
+		 */
+		virtual std::string bindDouble(double value) = 0;
+
+		/**
+		 * Bind an integer.
+		 *
+		 * @param value the integer
+		 * @return the string to use
+		 */
+		virtual std::string bindInteger(int value) = 0;
+
+		/**
+		 * Bind a string.
+		 *
+		 * @param value the string
+		 * @return the string to use
+		 */
+		virtual std::string bindString(std::string value) = 0;
+	};
+
+	using Ptr	= std::shared_ptr<Impl>;
+
+private:
+	size_t		m_pos;
+	int		m_params;
+	std::string	m_command;
+	Ptr		m_impl;
+
+	void assertCorrect();
+
+	void setValue(const std::string &value);
+
+public:
+	DriverRequest(Ptr impl, const std::string &command);
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~DriverRequest();
+
+	/**
+	 * Bind a value.
+	 *
+	 * @param value the value
+	 */
+	template <typename T>
+	void bind(T value)
+	{
+		static_assert(DriverTypeInfo<T>::value, "unsupported type");
+
+		setValue(DriverTypeInfo<T>::bind(value));
+	}
+
+	/**
+	 * Convert the request to string.
+	 *
+	 * @return the request as a string
+	 */
+	operator std::string();
+};
+
+/**
+ * @class Driver
+ * @brief A generic SQL driver
+ *
+ * This class is used to connect to a database and execute SQL queries. It
+ * does not include any DBMS code and just call virtual functions for
+ * a simpler integration of new DBMS drivers.
+ */
+class Driver {
+public:
+	class Impl;
+
+	using Params	= std::unordered_map<std::string, std::string>;
+	using Ptr	= std::shared_ptr<Impl>;
+
+	class Impl {
+	public:
+		/**
+		 * Create a synchronous connection, it waits and block until
+		 * the connection is made up to a specified timeout max.
+		 *
+		 * @param params a list of parameters.
+		 */
+		virtual void connect(const Params &params) = 0;
+
+		/**
+		 * Prepare a request with the specified SQL command.
+		 *
+		 * @param command the SQL command to parse and bind
+		 * @return a request to use with query
+		 * @see query
+		 */
+		virtual DriverRequest prepare(const std::string &command) = 0;
+	
+		/**
+		 * Execute a query.
+		 *
+		 * @param query the SQL command
+		 * @return a result
+		 * @throw Query::Error on failure
+		 */
+		virtual DriverQuery query(const std::string &command) = 0;
+
+		/**
+		 * Get the driver connection description.
+		 *
+		 * @return the description
+		 */
+		virtual std::string description() const = 0;
+
+		/**
+		 * Get the driver version as a string.
+		 *
+		 * @return the version
+		 */
+		virtual std::string version() const = 0;
+	};
+
+protected:
+	Ptr		m_impl;
+
+public:
+	Driver() = default;
+
+	/**
+	 * Virtual destructor.
+	 */
+	virtual ~Driver() = default;
+
+	/**
+	 * Wrapper for std::string variant.
+	 *
+	 * @param request the request to use
+	 * @return a result
+	 * @throw Query::Error on failure
+	 */
+	DriverQuery query(DriverRequest request);
+
+	/**
+	 * Create a synchronous connection, it waits and block until
+	 * the connection is made up to a specified timeout max.
+	 *
+	 * @param params a list of parameters.
+	 */
+	void connect(const Params &params);
+
+	/**
+	 * Prepare a request with the specified SQL command.
+	 *
+	 * @param command the SQL command to parse and bind
+	 * @return a request to use with query
+	 * @see query
+	 */
+	DriverRequest prepare(const std::string &command);
+
+	/**
+	 * Execute a query.
+	 *
+	 * @param query the SQL command
+	 * @return a result
+	 * @throw Query::Error on failure
+	 */
+	DriverQuery query(const std::string &command);
+
+	/**
+	 * Get the driver connection description.
+	 *
+	 * @return the description
+	 */
+	std::string description() const;
+
+	/**
+	 * Get the driver version as a string.
+	 *
+	 * @return the version
+	 */
+	std::string version() const;
+};
+
+template <>
+struct DriverTypeInfo<bool> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Boolean;
+
+	static bool get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getBoolean(row, column);
+	}
+
+	static void bind(DriverRequest &request, bool value)
+	{
+		request.m_impl->bindBoolean(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<time_t> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Date;
+
+	static time_t get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getDate(row, column);
+	}
+
+	static void bind(DriverRequest &request, time_t value)
+	{
+		request.m_impl->bindDate(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<double> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Double;
+
+	static double get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getDouble(row, column);
+	}
+
+	static void bind(DriverRequest &request, double value)
+	{
+		request.m_impl->bindDouble(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<int> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Integer;
+
+	static int get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getInt(row, column);
+	}
+
+	static void bind(DriverRequest &request, int value)
+	{
+		request.m_impl->bindInteger(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<std::string> : std::true_type {
+	static const DriverColumn	type = DriverColumn::String;
+
+	static std::string get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getString(row, column);
+	}
+
+	static void bind(DriverRequest &request, const std::string &value)
+	{
+		request.m_impl->bindString(value);
+	}
+};
+
+#endif // !_DRIVER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Driver/DriverPostgres.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,482 @@
+/*
+ * DriverPostgres.cpp -- PostgreSQL driver
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cerrno>
+#include <cstring>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+#include <vector>
+
+#include <libpq-fe.h>
+
+#include "DriverPostgres.h"
+
+namespace {
+
+using PostgresResult	= std::shared_ptr<PGresult>;
+using PostgresConn	= std::shared_ptr<PGconn>;
+
+}
+
+/**
+ * @class QueryPostgres
+ * @brief Query implementation for PostgreSQL.
+ */
+class QueryPostgresImpl : public DriverQuery::Impl {
+private:
+	PostgresConn	m_connection;
+	PostgresResult	m_result;
+
+public:
+	/**
+	 * Constructor used by DriverPostgres
+	 *
+	 * @param result the result
+	 */
+	QueryPostgresImpl(PostgresConn conn, PostgresResult result);
+
+	/**
+	 * @copydoc Query::getBoolean
+	 */
+	virtual bool getBoolean(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::getDate
+	 */
+	virtual time_t getDate(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::getDouble
+	 */
+	virtual double getDouble(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::getInt
+	 */
+	virtual int getInt(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::getString
+	 */
+	virtual std::string getString(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::type
+	 */
+	virtual DriverColumn type(const std::string &column) const;
+
+	/**
+	 * @copydoc Query::countRows
+	 */
+	virtual int countRows();
+
+	/**
+	 * @copydoc Query::countColumns
+	 */
+	virtual int countColumns();
+
+	/**
+	 * @copydoc Query::isNull
+	 */
+	virtual bool isNull(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::dump
+	 */
+	virtual void dump();
+};
+
+QueryPostgresImpl::QueryPostgresImpl(PostgresConn conn, PostgresResult result)
+	: m_connection(conn)
+	, m_result(result)
+{
+}
+
+DriverColumn QueryPostgresImpl::type(const std::string &column) const
+{
+	DriverColumn type;
+	int pqType, index;
+	
+	index = PQfnumber(m_result.get(), column.c_str());
+	pqType = PQftype(m_result.get(), index);
+	switch (pqType) {
+	case 16:
+		type = DriverColumn::Boolean;
+		break;
+	case 1082:
+	case 1083:
+	case 1114:
+	case 1184:
+		type = DriverColumn::Date;
+		break;
+	case 1700:
+	case 700:
+	case 701:
+		type = DriverColumn::Double;
+		break;
+	case 20:
+	case 21:
+	case 23:
+		type = DriverColumn::Integer;
+		break;
+	case 25:
+	case 1042:
+	case 1043:
+		type = DriverColumn::String;
+		break;
+	default:
+		type = DriverColumn::Invalid;
+	}
+
+	return type;
+}
+
+int QueryPostgresImpl::countRows()
+{
+	return PQntuples(m_result.get());
+}
+
+int QueryPostgresImpl::countColumns()
+{
+	return PQnfields(m_result.get());
+}
+
+bool QueryPostgresImpl::isNull(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return PQgetisnull(m_result.get(), row, idx) == 1;
+}
+
+void QueryPostgresImpl::dump(void)
+{
+	std::cout << "Dumping PostgreSQL result, ";
+	std::cout << countRows() << " rows, ";
+	std::cout << countColumns() << " columns" << std::endl;
+
+	for (int r = 0; r < countRows(); ++r) {
+		std::cout << "Dumping row " << r << std::endl;
+		std::cout << "==============================" << std::endl;
+
+		for (int c = 0; c < countColumns(); ++c) {
+			std::cout << "\t" << PQfname(m_result.get(), c);
+			std::cout << " = " << PQgetvalue(m_result.get(), r, c) << std::endl;
+		}
+	}
+}
+
+bool QueryPostgresImpl::getBoolean(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+	std::string code = PQgetvalue(m_result.get(), row, idx);
+
+	return code[0] == 't';
+}
+
+time_t QueryPostgresImpl::getDate(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+	time_t timestamp = std::time(nullptr);
+
+	try {
+		std::ostringstream oss;
+		std::string value, req;
+
+		value = PQgetvalue(m_result.get(), row, idx);
+
+		/*
+		 * Convert the date using the SQL function so that user does
+		 * not require any explicit conversion itself.
+		 */
+		printf("%s\n", value.c_str());
+		oss << "Select EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '";
+		oss << value;
+		oss << "') AS RESULT";
+		req = oss.str();
+
+		auto info = PQexec(m_connection.get(), oss.str().c_str());
+		auto status = PQresultStatus(info);
+
+		if (info != nullptr && (status == PGRES_COMMAND_OK ||
+		    status == PGRES_TUPLES_OK))
+		{
+			timestamp = atoi(PQgetvalue(info, 0, 0));
+			PQclear(info);
+		}
+	} catch (...) { }
+
+	return timestamp;
+}
+
+double QueryPostgresImpl::getDouble(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return std::stod(PQgetvalue(m_result.get(), row, idx));
+}
+
+int QueryPostgresImpl::getInt(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return std::stoi(PQgetvalue(m_result.get(), row, idx));
+}
+
+std::string QueryPostgresImpl::getString(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return std::string(PQgetvalue(m_result.get(), row, idx));
+}
+
+/* --------------------------------------------------------
+ * Request PostgreSQL Impl
+ * -------------------------------------------------------- */
+
+/**
+ * @class RequestPostgres
+ * @brief Request implementation for PostgreSQL.
+ */
+class RequestPostgres : public DriverRequest::Impl {
+private:
+	std::shared_ptr<PGconn> m_connection;
+
+protected:
+	/**
+	 * @copydoc Request::bindBoolean
+	 */
+	virtual std::string bindBoolean(bool value);
+
+	/**
+	 * @copydoc Request::bindDate
+	 */
+	virtual std::string bindDate(time_t value);
+
+	/**
+	 * @copydoc Request::bindDouble
+	 */
+	virtual std::string bindDouble(double value);
+
+	/**
+	 * @copydoc Request::bindInteger
+	 */
+	virtual std::string bindInteger(int value);
+
+	/**
+	 * @copydoc Request::bindString
+	 */
+	virtual std::string bindString(std::string value);
+
+public:
+	/**
+	 * Construct a request for PostgreSQL.
+	 *
+	 * @param conn the connection
+	 * @param command the command
+	 */
+	RequestPostgres(PostgresConn &conn);
+};
+
+RequestPostgres::RequestPostgres(PostgresConn &conn)
+{
+	m_connection = conn;
+}
+
+std::string RequestPostgres::bindBoolean(bool value)
+{
+	return (value) ? "'t'" : "'f'";
+}
+
+std::string RequestPostgres::bindDate(time_t value)
+{
+	std::ostringstream oss;
+
+	oss << "to_timestamp(" << value << ")";
+
+	return oss.str();
+}
+
+std::string RequestPostgres::bindDouble(double value)
+{
+	return std::to_string(value);
+}
+
+std::string RequestPostgres::bindInteger(int value)
+{
+	return std::to_string(value);
+}
+
+std::string RequestPostgres::bindString(std::string value)
+{
+	std::string result;
+	char *tmp;
+
+	tmp = PQescapeLiteral(m_connection.get(), value.c_str(), value.length());
+	if (tmp == nullptr)
+		return "";
+
+	result = std::string(tmp);
+	PQfreemem(tmp);
+
+	return result;
+}
+
+/* --------------------------------------------------------
+ * Driver PostgreSQL impl
+ * -------------------------------------------------------- */
+
+/**
+ * @class DriverPostgres
+ * @brief Driver implementation for PostgreSQL.
+ */
+class DriverPostgresImpl : public Driver::Impl {
+private:
+	PostgresConn m_connection;
+
+	/**
+	 * Convert the Params from the config
+	 * to the PostgreSQL string.
+	 *
+	 * @param settings the table
+	 * @return a string to be used
+	 */
+	std::string convert(Driver::Params &settings);
+
+public:
+	/**
+	 * @copydoc Driver::connect
+	 */
+	virtual void connect(const Driver::Params &params);
+
+	/**
+	 * @copydoc Driver::prepare
+	 */
+	virtual DriverRequest prepare(const std::string &command);
+
+	/**
+	 * @copydoc Driver::query
+	 */
+	virtual DriverQuery query(const std::string &command);
+
+	/**
+	 * @copydoc Driver::description
+	 */
+	virtual std::string description() const;
+
+	/**
+	 * @copydoc Driver::version
+	 */
+	virtual std::string version() const;
+};
+
+std::string DriverPostgresImpl::convert(Driver::Params &params)
+{
+	std::ostringstream oss;
+	std::vector<std::string> required { "host", "port", "user", "database", "password" };
+
+	for (auto s : required)
+		if (params.count(s) <= 0)
+			throw std::runtime_error("missing parameter " + s);
+
+	oss << "host = " << params["host"] << " ";
+	oss << "port = " << params["port"] << " ";
+	oss << "user = " << params["user"] << " ";
+	oss << "dbname = " << params["database"] << " ";
+	oss << "password = " << params["password"];
+
+	return oss.str();
+}
+
+void DriverPostgresImpl::connect(const Driver::Params &params)
+{
+	auto copy = params;
+	auto conn = PQconnectdb(convert(copy).c_str());
+
+	if (conn == nullptr)
+		throw std::runtime_error(std::strerror(ENOMEM));
+
+	if (PQstatus(conn) == CONNECTION_BAD) {
+		auto error = PQerrorMessage(conn);
+		PQfinish(conn);
+
+		throw std::runtime_error(error);
+	}
+
+	m_connection = std::shared_ptr<PGconn>(conn, PQfinish);
+}
+
+DriverRequest DriverPostgresImpl::prepare(const std::string &command)
+{
+	return DriverRequest(std::make_shared<RequestPostgres>(m_connection), command);
+}
+
+DriverQuery DriverPostgresImpl::query(const std::string &cmd)
+{
+	PGresult *info;
+
+	// If NULL, the libpq said no memory
+	info = PQexec(m_connection.get(), cmd.c_str());
+	if (info == nullptr)
+		throw std::runtime_error(strerror(ENOMEM));
+
+	// If an error occured
+	int errorCode = PQresultStatus(info);
+	if (errorCode != PGRES_COMMAND_OK && errorCode != PGRES_TUPLES_OK) {
+		auto error = PQresultErrorMessage(info);
+		PQclear(info);
+
+		throw std::runtime_error(error);
+	}
+
+	auto result = std::shared_ptr<PGresult>(info, PQclear);
+	auto impl = std::make_shared<QueryPostgresImpl>(m_connection, result);
+
+	return DriverQuery(impl);
+}
+
+std::string DriverPostgresImpl::description() const
+{
+	std::ostringstream oss;
+
+	oss << "Connected on PostgreSQL database: " << std::endl;
+	oss << "  host: " << PQhost(m_connection.get()) << std::endl;
+	oss << "  port: " << PQport(m_connection.get()) << std::endl;
+	oss << "  user: " << PQuser(m_connection.get()) << std::endl;
+	oss << "  database: " << PQdb(m_connection.get()) << std::endl;
+
+	return oss.str();
+}
+
+std::string DriverPostgresImpl::version() const
+{
+	std::ostringstream oss;
+
+	oss << "PostgreSQL driver (version " << PQlibVersion() << ")";
+
+	return oss.str();
+}
+
+/* --------------------------------------------------------
+ * Driver PostgreSQL
+ * -------------------------------------------------------- */
+
+DriverPostgres::DriverPostgres()
+{
+	m_impl = std::make_shared<DriverPostgresImpl>();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Driver/DriverPostgres.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,33 @@
+/*
+ * DriverPostgres.h -- PostgreSQL driver
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS
+ */
+
+#ifndef _DRIVER_PG_H_
+#define _DRIVER_PG_H_
+
+#include "Driver.h"
+
+class DriverPostgres : public Driver {
+public:
+	DriverPostgres();
+};
+
+#endif // !_DRIVER_PG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Dynlib/Dynlib.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,144 @@
+/*
+ * DynLib.cpp -- portable shared library loader
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdexcept>
+
+#if defined(_WIN32)
+#  include <Windows.h>
+#else
+#  include <dlfcn.h>
+#endif
+
+#include "Dynlib.h"
+
+#if defined(_WIN32)
+
+namespace {
+
+std::string systemError()
+{
+	LPSTR error = nullptr;
+	std::string errmsg = "Unknown error";
+
+	FormatMessageA(
+		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL,
+		GetLastError(),
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		(LPSTR)&error, 0, NULL);
+
+	if (error) {
+		errmsg = std::string(error);
+		LocalFree(error);
+	}
+
+	return errmsg;
+}
+
+}
+
+void Dynlib::systemInit()
+{
+	m_handle = nullptr;
+}
+
+Dynlib::Handle Dynlib::systemLoad(const std::string &path, Policy policy) const
+{
+	Handle handle = LoadLibraryA(path.c_str());
+
+	if (handle == nullptr)
+		throw std::runtime_error(systemError());
+
+	return handle;
+}
+
+Dynlib::Sym Dynlib::systemSym(const std::string &name)
+{
+	Sym sym;
+
+	if (m_handle == nullptr)
+		throw std::runtime_error("library not loaded");
+
+	sym = GetProcAddress(m_handle, name.c_str());
+	if (sym == nullptr)
+		throw std::out_of_range(systemError());
+
+	return sym;
+}
+
+void Dynlib::systemClose()
+{
+	if (m_handle != nullptr)
+		FreeLibrary(m_handle);
+}
+
+#else
+
+void Dynlib::systemInit()
+{
+	m_handle = nullptr;
+}
+
+Dynlib::Handle Dynlib::systemLoad(const std::string &path, Policy policy) const
+{
+	int mode = (policy == Immediately) ? RTLD_NOW : RTLD_LAZY;
+	Handle handle;
+
+	handle = dlopen(path.c_str(), mode);
+	if (handle == nullptr)
+		throw std::runtime_error(dlerror());
+
+	return handle;
+}
+
+Dynlib::Sym Dynlib::systemSym(const std::string &name)
+{
+	Sym sym;
+
+	if (m_handle == nullptr)
+		throw std::runtime_error("library not loaded");
+
+	sym = dlsym(m_handle, name.c_str());
+	if (sym == nullptr)
+		throw std::out_of_range(dlerror());
+
+	return sym;
+}
+
+void Dynlib::systemClose()
+{
+	if (m_handle != nullptr)
+		dlclose(m_handle);
+}
+
+#endif
+
+Dynlib::Dynlib()
+{
+	systemInit();
+}
+
+Dynlib::Dynlib(const std::string &path, Policy policy)
+{
+	m_handle = systemLoad(path, policy);
+}
+
+Dynlib::~Dynlib()
+{
+	systemClose();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Dynlib/Dynlib.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,103 @@
+/*
+ * DynLib.h -- portable shared library loader
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DYNLIB_H_
+#define _DYNLIB_H_
+
+#include <string>
+
+#if defined(_WIN32)
+#  include <Windows.h>
+#  define DYNLIB_EXPORT	__declspec(dllexport)
+#else
+#  define DYNLIB_EXPORT
+#endif
+
+/**
+ * @class Dynlib
+ * @brief Load a dynamic module
+ *
+ * This class is a portable wrapper to load shared libraries on
+ * supported systems.
+ */
+class Dynlib {
+public:
+#if defined(_WIN32)
+	using Handle	= HMODULE;
+	using Sym	= FARPROC;
+#else
+	using Handle	= void *;
+	using Sym	= void *;
+#endif
+
+	enum Policy {
+		Immediately,		//! load symbols immediately
+		Lazy			//! load symbols when needed
+	};
+
+private:
+	Handle	m_handle;
+
+	void	systemInit();
+	Handle	systemLoad(const std::string &path, Policy policy) const;
+	Sym	systemSym(const std::string &name);
+	void	systemClose();
+
+public:
+	/**
+	 * Copy is forbidden.
+	 */
+	Dynlib(const Dynlib &) = delete;
+	Dynlib &operator=(const Dynlib &) = delete;
+
+	/**
+	 * Default constructor.
+	 */
+	Dynlib();
+
+	/**
+	 * Constructor to load a shared module. The path must
+	 * be absolute.
+	 *
+	 * @param path the absolute path
+	 * @param policy the policy to load
+	 * @throw std::runtime_error on error
+	 */
+	Dynlib(const std::string &path, Policy policy = Immediately);
+
+	/**
+	 * Close the library automatically.
+	 */
+	~Dynlib();
+
+	/**
+	 * Get a symbol from the library.
+	 *
+	 * @param name the symbol
+	 * @return the symbol
+	 * @throw std::runtime_error on error
+	 * @throw std::out_of_range if not found
+	 */
+	template <typename T>
+	T sym(const std::string &name)
+	{
+		return reinterpret_cast<T>(systemSym(name));
+	}
+};
+
+#endif // !_DYNLIB_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Flags/Flags.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,341 @@
+/*
+ * Flags.h -- safe wrapper for enum flags
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FLAGS_H_
+#define _FLAGS_H_
+
+/**
+ * @file Flags.h
+ * @brief Provide template class Flags and operators for enum classes
+ */
+
+#include <type_traits>
+
+/**
+ * @class Flags
+ * @brief Wrapper that store enum flags
+ *
+ * This class is used to store an enum and make bitwise operations on it. User do not need
+ * to supply these operators because they are implemented in the class.
+ *
+ * This class is very cheap and store the real underlying type from the enum and all functions
+ * are inlined.
+ */
+template <typename Enum, typename Type = std::underlying_type_t<Enum>>
+class Flags final {
+private:
+	Type m_value { 0 };
+	
+public:
+	/**
+	 * Construct flags to 0.
+	 */
+	constexpr Flags() noexcept = default;
+
+	/**
+	 * Construct flags with the enum value.
+	 *
+	 * @param m the mask
+	 */
+	constexpr Flags(Enum m) noexcept
+		: m_value(static_cast<Type>(m))
+	{
+	}
+
+	/**
+	 * Construct flags with the enum value.
+	 *
+	 * @param m the mask
+	 */
+	constexpr Flags(Type m) noexcept
+		: m_value(m)
+	{
+	}
+
+	/**
+	 * Move constructor.
+	 *
+	 * @param other the other
+	 */
+	inline Flags(Flags &&other) noexcept = default;
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param other the other
+	 */
+	inline Flags(const Flags &other) noexcept = default;
+
+	/**
+	 * Move operator.
+	 *
+	 * @param other the other
+	 */
+	inline Flags &operator=(Flags &&other) noexcept = default;
+
+	/**
+	 * Copy operator.
+	 *
+	 * @param other the other
+	 */
+	inline Flags &operator=(const Flags &other) noexcept = default;
+
+	/**
+	 * &= operator.
+	 *
+	 * @param m the mask
+	 * @return *this
+	 */
+	inline Flags &operator&=(Enum m) noexcept
+	{
+		m_value &= static_cast<Type>(m);
+
+		return *this;
+	}
+	
+	/**
+	 * &= operator.
+	 *
+	 * @param m the mask
+	 * @return *this
+	 */
+	inline Flags &operator&=(Type m) noexcept
+	{
+		m_value &= m;
+
+		return *this;
+	}
+
+	/**
+	 * |= operator.
+	 *
+	 * @param m the mask
+	 * @return *this
+	 */
+	inline Flags &operator|=(Enum m) noexcept
+	{
+		m_value |= static_cast<Type>(m);
+
+		return *this;
+	}
+	
+	/**
+	 * |= operator.
+	 *
+	 * @param m the mask
+	 * @return *this
+	 */
+	inline Flags &operator|=(Type m) noexcept
+	{
+		m_value |= m;
+
+		return *this;
+	}
+
+	/**
+	 * ^= operator.
+	 *
+	 * @param m the mask
+	 * @return *this
+	 */
+	inline Flags &operator^=(Enum m) noexcept
+	{
+		m_value ^= static_cast<Type>(m);
+
+		return *this;
+	}
+	
+	/**
+	 * ^= operator.
+	 *
+	 * @param m the mask
+	 * @return *this
+	 */
+	inline Flags &operator^=(Type m) noexcept
+	{
+		m_value ^= m;
+
+		return *this;
+	}
+
+	/**
+	 * & operator.
+	 *
+	 * @param m the mask
+	 * @return & combination
+	 */
+	constexpr Flags operator&(Enum m) const noexcept
+	{
+		return m_value & static_cast<Type>(m);
+	}
+
+	/**
+	 * & operator.
+	 *
+	 * @param m the mask
+	 * @return & combination
+	 */
+	constexpr Flags operator&(Type m) const noexcept
+	{
+		return m_value & m;
+	}
+
+	/**
+	 * | operator.
+	 *
+	 * @param m the mask
+	 * @return | combination
+	 */
+	constexpr Flags operator|(Enum m) const noexcept
+	{
+		return m_value | static_cast<Type>(m);
+	}
+	
+	/**
+	 * | operator.
+	 *
+	 * @param m the mask
+	 * @return | combination
+	 */
+	constexpr Flags operator|(Type m) const noexcept
+	{
+		return m_value | m;
+	}
+
+	/**
+	 * ^ operator.
+	 *
+	 * @param m the mask
+	 * @return ^ combination
+	 */
+	constexpr Flags operator^(Enum m) const noexcept
+	{
+		return m_value & static_cast<Type>(m);
+	}
+
+	/**
+	 * ^ operator.
+	 *
+	 * @param m the mask
+	 * @return ^ combination
+	 */
+	constexpr Flags operator^(Type m) const noexcept
+	{
+		return m_value & m;
+	}
+
+	/**
+	 * ~ unary operator.
+	 *
+	 * @return ~
+	 */
+	constexpr Flags operator~() const noexcept
+	{
+		return ~m_value;
+	}
+
+	/**
+	 * Convert to bool. Simply check if value is not 0.
+	 *
+	 * @return true if value != 0
+	 */
+	constexpr operator bool() const noexcept
+	{
+		return m_value != 0;
+	}
+
+	/**
+	 * Operator !. Simply check if value is 0.
+	 *
+	 * @return true if value == 0
+	 */
+	constexpr bool operator!() const noexcept
+	{
+		return m_value == 0;
+	}
+
+	/**
+	 * Test comparison with other mask.
+	 *
+	 * @return true if this value == m
+	 */
+	constexpr bool operator==(Enum m) const noexcept
+	{
+		return m_value == static_cast<Type>(m);
+	}
+
+	/**
+	 * Test comparison with other mask.
+	 *
+	 * @return true if this value == m
+	 */
+	constexpr bool operator==(Type m) const noexcept
+	{
+		return m_value == m;
+	}
+};
+
+/**
+ * Apply & operator on the enum.
+ *
+ * @param x1 the first value
+ * @param x2 the second value
+ */
+template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
+constexpr Value operator&(Value x1, Value x2) noexcept
+{
+	return static_cast<Value>(static_cast<Type>(x1) & static_cast<Type>(x2));
+}
+
+/**
+ * Apply | operator on the enum.
+ *
+ * @param x1 the first value
+ * @param x2 the second value
+ */
+template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
+constexpr Value operator|(Value x1, Value x2) noexcept
+{
+	return static_cast<Value>(static_cast<Type>(x1) | static_cast<Type>(x2));
+}
+
+/**
+ * Apply ^ operator on the enum.
+ *
+ * @param x1 the first value
+ * @param x2 the second value
+ */
+template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
+constexpr Value operator^(Value x1, Value x2) noexcept
+{
+	return static_cast<Value>(static_cast<Type>(x1) ^ static_cast<Type>(x2));
+}
+
+/**
+ * Apply ~ operator on the enum.
+ *
+ * @param x1 the first value
+ * @param x2 the second value
+ */
+template <typename Value, typename Type = std::enable_if_t<std::is_enum<Value>::value, std::underlying_type_t<Value>>>
+constexpr Value operator~(Value x) noexcept
+{
+	return static_cast<Value>(~static_cast<Type>(x));
+}
+
+#endif // !_FLAGS_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Hash/Hash.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,42 @@
+/*
+ * Hash.cpp -- hash functions
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "Hash.h"
+
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+
+std::string Hash::md5(const std::string &input)
+{
+	return convert<MD5_CTX, MD5_DIGEST_LENGTH>(input, MD5_Init, MD5_Update, MD5_Final);
+}
+
+std::string Hash::sha1(const std::string &input)
+{
+	return convert<SHA_CTX, SHA_DIGEST_LENGTH>(input, SHA1_Init, SHA1_Update, SHA1_Final);
+}
+
+std::string Hash::sha256(const std::string &input)
+{
+	return convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(input, SHA256_Init, SHA256_Update, SHA256_Final);
+}
+
+std::string Hash::sha512(const std::string &input)
+{
+	return convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(input, SHA512_Init, SHA512_Update, SHA512_Final);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Hash/Hash.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,100 @@
+/*
+ * Hash.h -- hash functions
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _HASH_H_
+#define _HASH_H_
+
+/**
+ * @file Hash.h
+ * @brief Hash functions
+ */
+
+#include <string>
+
+/**
+ * @class Hash
+ * @brief Hash functions
+ *
+ * Provide support for MD5, SHA1, SHA256 and SHA512.
+ */
+class Hash {
+private:
+	template <typename Context>
+	using Init	= int (*)(Context *);
+
+	template <typename Context>
+	using Update	= int (*)(Context *, const void *, size_t);
+
+	template <typename Context>
+	using Final	= int (*)(unsigned char *, Context *);
+
+	template <typename Context, size_t Length>
+	static std::string convert(const std::string &input,
+				   Init<Context> init,
+				   Update<Context> update,
+				   Final<Context> finalize)
+	{
+		unsigned char digest[Length];
+		char hash[Length * 2 + 1];
+		
+		Context ctx;
+		init(&ctx);
+		update(&ctx, input.c_str(), input.length());
+		finalize(digest, &ctx);
+		
+		for (unsigned long i = 0; i < Length; i++)
+			sprintf(&hash[i * 2], "%02x", (unsigned int)digest[i]);
+		
+		return std::string(hash);
+	}
+
+public:
+	/**
+	 * Hash using MD5.
+	 *
+	 * @param input the input string
+	 * @return the hashed string
+	 */
+	static std::string md5(const std::string &input);
+
+	/**
+	 * Hash using SHA1.
+	 *
+	 * @param input the input string
+	 * @return the hashed string
+	 */
+	static std::string sha1(const std::string &input);
+
+	/**
+	 * Hash using SHA256.
+	 *
+	 * @param input the input string
+	 * @return the hashed string
+	 */
+	static std::string sha256(const std::string &input);
+
+	/**
+	 * Hash using SHA512.
+	 *
+	 * @param input the input string
+	 * @return the hashed string
+	 */
+	static std::string sha512(const std::string &input);
+};
+
+#endif // !_HASH_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Ini/Ini.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,425 @@
+/*
+ * Ini.cpp -- .ini file parsing
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cctype>
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+#if defined(_WIN32)
+#  include <Shlwapi.h>	// for PathIsRelative
+#endif
+
+#include "Ini.h"
+
+namespace {
+
+/* --------------------------------------------------------
+ * Tokens
+ * -------------------------------------------------------- */
+
+enum class TokenType {
+	Comment = '#',
+	SectionBegin = '[',
+	SectionEnd = ']',
+	Escape = '\\',
+	QuoteSimple = '\'',
+	QuoteDouble = '"',
+	NewLine = '\n',
+	Assign = '=',
+	Include = '@',
+	Word,
+	Space
+};
+
+class Token {
+private:
+	TokenType m_type;
+	int m_line;
+	int m_position;
+	std::string m_value;
+
+public:
+	inline Token(TokenType type, int line, int position, std::string value = "")
+		: m_type(type)
+		, m_line(line)
+		, m_position(position)
+		, m_value(std::move(value))
+	{
+	}
+
+	inline TokenType type() const noexcept
+	{
+		return m_type;
+	}
+
+	inline int line() const noexcept
+	{
+		return m_line;
+	}
+
+	inline int position() const noexcept
+	{
+		return m_position;
+	}
+
+	inline std::string value() const
+	{
+		switch (m_type) {
+		case TokenType::Comment:
+			return "#";
+		case TokenType::SectionBegin:
+			return "[";
+		case TokenType::SectionEnd:
+			return "]";
+		case TokenType::QuoteSimple:
+			return "'";
+		case TokenType::QuoteDouble:
+			return "\"";
+		case TokenType::NewLine:
+			return "\n";
+		case TokenType::Assign:
+			return "=";
+		case TokenType::Include:
+			return "@";
+		case TokenType::Space:
+			return m_value;
+		case TokenType::Word:
+			return m_value;
+		default:
+			break;
+		}
+
+		return "";
+	}
+
+	inline std::string toString() const
+	{
+		switch (m_type) {
+		case TokenType::Comment:
+			return "'#'";
+		case TokenType::SectionBegin:
+			return "'['";
+		case TokenType::SectionEnd:
+			return "']'";
+		case TokenType::QuoteSimple:
+			return "'";
+		case TokenType::QuoteDouble:
+			return "\"";
+		case TokenType::NewLine:
+			return "<newline>";
+		case TokenType::Assign:
+			return "=";
+		case TokenType::Include:
+			return "@";
+		case TokenType::Space:
+			return "<blank>";
+		case TokenType::Word:
+			return "`" + m_value + "'";
+		default:
+			break;
+		}
+
+		return "";
+	}
+};
+
+using TokenStack = std::vector<Token>;
+
+/* --------------------------------------------------------
+ * IniBuilder
+ * -------------------------------------------------------- */
+
+class IniBuilder {
+private:
+	std::string m_path;
+	std::string m_base;
+	Ini &m_ini;
+
+private:
+	inline bool isReserved(char c) const noexcept
+	{
+		return c == '\n' || c == '#' || c == '"' || c == '\'' || c == '=' || c == '[' || c == ']' || c == '@';
+	}
+
+	std::string base(std::string path)
+	{
+		auto pos = path.find_last_of("/\\");
+
+		if (pos != std::string::npos) {
+			path.erase(pos);
+		} else {
+			path = ".";
+		}
+
+		return path;
+	}
+
+#if defined(_WIN32)
+	bool isAbsolute(const std::string &path)
+	{
+		return !PathIsRelative(path.c_str());
+	}
+#else
+	bool isAbsolute(const std::string &path)
+	{
+		return path.size() > 0 && path[0] == '/';
+	}
+#endif
+
+	std::vector<Token> analyze(std::istream &stream) const
+	{
+		std::istreambuf_iterator<char> it(stream);
+		std::istreambuf_iterator<char> end;
+		std::vector<Token> tokens;
+
+		int lineno{1};
+		int position{0};
+
+		while (it != end) {
+			std::string value;
+
+			if (isReserved(*it)) {
+				while (it != end && isReserved(*it)) {
+					// Single character tokens
+					switch (*it) {
+					case '\n':
+						++lineno;
+						position = 0;
+					case '#':
+					case '[':
+					case ']':
+					case '\'':
+					case '"':
+					case '=':
+					case '@':
+						tokens.push_back({ static_cast<TokenType>(*it), lineno, position });
+						++it;
+						++position;
+					default:
+						break;
+					}
+				}
+			} else if (std::isspace(*it)) {
+				while (it != end && std::isspace(*it) && *it != '\n') {
+					value.push_back(*it++);
+				}
+
+				tokens.push_back({ TokenType::Space, lineno, position, std::move(value) });
+			} else {
+				while (it != end && !std::isspace(*it) && !isReserved(*it)) {
+					value.push_back(*it++);
+				}
+
+				tokens.push_back({ TokenType::Word, lineno, position, std::move(value) });
+			}
+		}
+
+		return tokens;
+	}
+
+	void readComment(TokenStack::iterator &it, TokenStack::iterator end)
+	{
+		while (it != end && it->type() != TokenType::NewLine) {
+			++ it;
+		}
+
+		// remove new line
+		++ it;
+	}
+
+	void readSpace(TokenStack::iterator &it, TokenStack::iterator end)
+	{
+		while (it != end && it->type() == TokenType::Space) {
+			++ it;
+		}
+	}
+
+	void readNewLine(TokenStack::iterator &it, TokenStack::iterator end)
+	{
+		while (it != end && it->type() == TokenType::NewLine) {
+			++ it;
+		}
+	}
+
+	IniSection readSection(TokenStack::iterator &it, TokenStack::iterator end)
+	{
+		if (++it == end || it->type() != TokenType::Word) {
+			throw IniError(it->line(), it->position(), "word expected after [, got " + it->toString());
+		}
+
+		IniSection section(it->value());
+
+		if (++it == end || it->type() != TokenType::SectionEnd) {
+			throw IniError(it->line(), it->position(), "] expected, got " + it->toString());
+		}
+
+		// Remove ]
+		++ it;
+
+		if (it == end) {
+			return section;
+		}
+
+		while (it != end && it->type() != TokenType::SectionBegin) {
+			if (it->type() == TokenType::Space) {
+				readSpace(it, end);
+			} else if (it->type() == TokenType::NewLine) {
+				readNewLine(it, end);
+			} else if (it->type() == TokenType::Comment) {
+				readComment(it, end);
+			} else if (it->type() == TokenType::Word) {
+				section.push_back(readOption(it, end));
+			} else {
+				throw IniError(it->line(), it->position(), "unexpected token " + it->toString());
+			}
+		}
+
+		return section;
+	}
+
+	IniOption readOption(TokenStack::iterator &it, TokenStack::iterator end)
+	{
+		std::string key = it->value();
+
+		if (++it == end) {
+			throw IniError(it->line(), it->position(), "expected '=' after option declaration, got <EOF>");
+		}
+
+		readSpace(it, end);
+
+		if (it == end || it->type() != TokenType::Assign) {
+			throw IniError(it->line(), it->position(), "expected '=' after option declaration, got " + it++->toString());
+		}
+
+		readSpace(++it, end);
+
+		std::ostringstream oss;
+
+		if (it->type() == TokenType::QuoteSimple || it->type() == TokenType::QuoteDouble) {
+			TokenStack::iterator save = it++;
+
+			while (it != end && it->type() != save->type()) {
+				oss << it++->value();
+			}
+
+			if (it == end)
+				throw IniError(save->line(), save->position(), "undisclosed quote: " + save->toString() + " expected");
+
+			++ it;
+		} else if (it->type() == TokenType::Word) {
+			oss << it++->value();
+		} else if (it->type() != TokenType::NewLine && it->type() != TokenType::Comment) {
+			// No value requested, must be NewLine or comment
+			throw IniError(it->line(), it->position(), "expected option value after '=', got " + it->toString());
+		}
+
+
+		return IniOption(std::move(key), oss.str());
+	}
+
+	void readInclude(TokenStack::iterator &it, TokenStack::iterator end)
+	{
+		if (++it == end || (it->type() != TokenType::Word || it->value() != "include")) {
+			throw IniError(it->line(), it->position(), "expected `include' after '@' token, got " + it->toString());
+		}
+
+		readSpace(++it, end);
+
+		// Quotes mandatory
+		TokenStack::iterator save = it;
+
+		if (it == end || (it->type() != TokenType::QuoteSimple && it->type() != TokenType::QuoteDouble)) {
+			throw IniError(it->line(), it->position(), "expected filename after @include statement");
+		}
+
+		// Filename
+		if (++it == end || it->type() != TokenType::Word) {
+			throw IniError(it->line(), it->position(), "expected filename after @include statement");
+		}
+
+		std::string value = it->value();
+		std::string fullpath;
+
+		if (isAbsolute(value)) {
+			fullpath = value;
+		} else {
+			fullpath = m_base + "/" + it->value();
+		}
+
+		// Must be closed with the same quote
+		if (++it == end || it->type() != save->type()) {
+			throw IniError(save->line(), save->position(), "undiclosed quote: " + save->toString() + " expected");
+		}
+
+		// Remove quote
+		++ it;
+
+		IniBuilder(m_ini, fullpath);
+	}
+
+public:
+	IniBuilder(Ini &ini, std::string path)
+		: m_path(path)
+		, m_base(base(std::move(path)))
+		, m_ini(ini)
+	{
+		std::ifstream file(m_path);
+
+		if (!file.is_open())
+			throw std::runtime_error(std::strerror(errno));
+
+		std::vector<Token> ts = analyze(file);
+
+		auto it = ts.begin();
+		auto end = ts.end();
+
+		while (it != end) {
+			if (it->type() == TokenType::Space) {
+				readSpace(it, end);
+			} else if (it->type() == TokenType::NewLine) {
+				readNewLine(it, end);
+			} else if (it->type() == TokenType::Comment) {
+				readComment(it, end);
+			} else if (it->type() == TokenType::Include) {
+				readInclude(it, end);
+			} else if (it->type() == TokenType::SectionBegin) {
+				m_ini.push_back(readSection(it, end));
+			} else {
+				throw IniError(it->line(), it->position(), "unexpected " + it->toString() + " on root document");
+			}
+		}
+	}
+};
+
+} // !namespace
+
+/* --------------------------------------------------------
+ * Ini
+ * -------------------------------------------------------- */
+
+Ini::Ini(const std::string &path)
+{
+	IniBuilder(*this, path);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Ini/Ini.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,494 @@
+/*
+ * Ini.h -- .ini file parsing
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _INI_H_
+#define _INI_H_
+
+/**
+ * @file Ini.h
+ * @brief Configuration file parser
+ */
+
+#include <algorithm>
+#include <deque>
+#include <stdexcept>
+#include <string>
+
+/**
+ * @class IniError
+ * @brief Error in a file
+ */
+class IniError : public std::exception {
+private:
+	int m_line;
+	int m_position;
+	std::string m_error;
+
+public:
+	/**
+	 * Construct an error.
+	 *
+	 * @param line the line
+	 * @param position the position
+	 * @param error the error
+	 */
+	inline IniError(int line, int position, std::string error)
+		: m_line(line)
+		, m_position(position)
+		, m_error(std::move(error))
+	{
+	}
+
+	/**
+	 * Return the line number.
+	 *
+	 * @return the line
+	 */
+	inline int line() const noexcept
+	{
+		return m_line;
+	}
+
+	/**
+	 * Return the position in the current line.
+	 *
+	 * @return the position
+	 */
+	inline int position() const noexcept
+	{
+		return m_position;
+	}
+
+	/**
+	 * Get the error string.
+	 *
+	 * @return the string
+	 */
+	inline const char *what() const noexcept
+	{
+		return m_error.c_str();
+	}
+};
+
+/**
+ * @class IniOption
+ * @brief Option definition
+ */
+class IniOption {
+private:
+	std::string m_key;
+	std::string m_value;
+
+public:
+	/**
+	 * Construct an option.
+	 *
+	 * @param key the key
+	 * @param value the value
+	 */
+	inline IniOption(std::string key, std::string value)
+		: m_key(std::move(key))
+		, m_value(std::move(value))
+	{
+	}
+
+	/**
+	 * Get the option key.
+	 *
+	 * @return the key
+	 */
+	inline const std::string &key() const noexcept
+	{
+		return m_key;
+	}
+
+	/**
+	 * Get the option value.
+	 *
+	 * @return the value
+	 */
+	inline const std::string &value() const noexcept
+	{
+		return m_value;
+	}
+};
+
+/**
+ * @class IniSection
+ * @brief Section that contains one or more options
+ */
+class IniSection {
+private:
+	std::string m_key;
+	std::deque<IniOption> m_options;
+
+	template <typename T>
+	T find(const std::string &key) const
+	{
+		auto it = std::find_if(m_options.begin(), m_options.end(), [&] (const IniOption &o) {
+			return o.key() == key;
+		});
+
+		if (it == m_options.end())
+			throw std::out_of_range("option " + key + " not found");
+
+		return const_cast<T>(*it);
+	}
+
+public:
+	/**
+	 * Default constructor has no sections and no values.
+	 */
+	IniSection() = default;
+
+	/**
+	 * Construct a section with a set of options.
+	 *
+	 * @param key the section name
+	 * @param options the list of options
+	 */
+	inline IniSection(std::string key, std::deque<IniOption> options = {}) noexcept
+		: m_key(std::move(key))
+		, m_options(std::move(options))
+	{
+	}
+
+	/**
+	 * Get the section key.
+	 *
+	 * @return the key
+	 */
+	inline const std::string &key() const noexcept
+	{
+		return m_key;
+	}
+
+	/**
+	 * Get an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() noexcept
+	{
+		return m_options.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() const noexcept
+	{
+		return m_options.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cbegin() const noexcept
+	{
+		return m_options.cbegin();
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() noexcept
+	{
+		return m_options.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() const noexcept
+	{
+		return m_options.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cend() const noexcept
+	{
+		return m_options.cend();
+	}
+
+	/**
+	 * Append an option.
+	 *
+	 * @param option the option to add
+	 */
+	inline void push_back(IniOption option)
+	{
+		m_options.push_back(std::move(option));
+	}
+
+	/**
+	 * Push an option to the beginning.
+	 *
+	 * @param option the option to add
+	 */
+	inline void push_front(IniOption option)
+	{
+		m_options.push_front(std::move(option));
+	}
+
+	/**
+	 * Get the number of options in that section.
+	 *
+	 * @return the size
+	 */
+	inline unsigned size() const noexcept
+	{
+		return m_options.size();
+	}
+
+	/**
+	 * Access an option at the specified index.
+	 *
+	 * @param index the index
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline IniOption &operator[](int index) noexcept
+	{
+		return m_options[index];
+	}
+
+	/**
+	 * Access an option at the specified index.
+	 *
+	 * @param index the index
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniOption &operator[](int index) const noexcept
+	{
+		return m_options[index];
+	}
+
+	/**
+	 * Access an option at the specified key.
+	 *
+	 * @param key the key
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline IniOption &operator[](const std::string &key)
+	{
+		return find<IniOption &>(key);
+	}
+
+	/**
+	 * Access an option at the specified key.
+	 *
+	 * @param key the key
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniOption &operator[](const std::string &key) const
+	{
+		return find<const IniOption &>(key);
+	}
+};
+
+/**
+ * @class Ini
+ * @brief Ini config file loader
+ */
+class Ini {
+private:
+	std::deque<IniSection> m_sections;
+
+	template <typename T>
+	T find(const std::string &key) const
+	{
+		auto it = std::find_if(m_sections.begin(), m_sections.end(), [&] (const IniSection &s) {
+			return s.key() == key;
+		});
+
+		if (it == m_sections.end())
+			throw std::out_of_range("section " + key + " not found");
+
+		return const_cast<T>(*it);
+	}
+
+public:
+	/**
+	 * Default constructor with an empty configuration.
+	 */
+	Ini() = default;
+
+	/**
+	 * Open the path as the configuration file.
+	 *
+	 * @param path the path
+	 * @throw IniError on any error
+	 */
+	Ini(const std::string &path);
+
+	/**
+	 * Get an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() noexcept
+	{
+		return m_sections.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() const noexcept
+	{
+		return m_sections.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cbegin() const noexcept
+	{
+		return m_sections.cbegin();
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() noexcept
+	{
+		return m_sections.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() const noexcept
+	{
+		return m_sections.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cend() const noexcept
+	{
+		return m_sections.cend();
+	}
+
+	/**
+	 * Get the number of sections in the configuration.
+	 *
+	 * @return the size
+	 */
+	inline unsigned size() const noexcept
+	{
+		return m_sections.size();
+	}
+
+	/**
+	 * Append a section to the end.
+	 *
+	 * @param section the section to add
+	 */
+	inline void push_back(IniSection section)
+	{
+		m_sections.push_back(std::move(section));
+	}
+
+	/**
+	 * Add a section to the beginning.
+	 *
+	 * @param section the section to add
+	 */
+	inline void push_front(IniSection section)
+	{
+		m_sections.push_front(std::move(section));
+	}
+
+	/**
+	 * Access a section at the specified index.
+	 *
+	 * @param index the index
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline IniSection &operator[](int index) noexcept
+	{
+		return m_sections[index];
+	}
+
+	/**
+	 * Access a section at the specified index.
+	 *
+	 * @param index the index
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniSection &operator[](int index) const noexcept
+	{
+		return m_sections[index];
+	}
+
+	/**
+	 * Access a section at the specified key.
+	 *
+	 * @param key the key
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline IniSection &operator[](const std::string &key)
+	{
+		return find<IniSection &>(key);
+	}
+
+	/**
+	 * Access a section at the specified key.
+	 *
+	 * @param key the key
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniSection &operator[](const std::string &key) const
+	{
+		return find<IniSection &>(key);
+	}
+};
+
+#endif // !_INI_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Json/Json.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,158 @@
+/*
+ * Json.cpp -- jansson C++11 wrapper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdexcept>
+
+#include "Json.h"
+
+/* --------------------------------------------------------
+ * JsonObject
+ * -------------------------------------------------------- */
+
+JsonObject JsonValue::toObject() const noexcept
+{
+	json_incref(m_handle.get());
+
+	return JsonObject(m_handle.get());
+}
+
+JsonArray JsonValue::toArray() const noexcept
+{
+	json_incref(m_handle.get());
+
+	return JsonArray(m_handle.get());
+}
+
+/* --------------------------------------------------------
+ * JsonArray
+ * -------------------------------------------------------- */
+
+JsonValue JsonArray::at(int index) const
+{
+	auto value = json_array_get(m_handle.get(), index);
+
+	if (value == nullptr)
+		throw JsonError("index out of bounds");
+
+	json_incref(value);
+
+	return JsonValue{value};
+}
+
+JsonValue JsonArray::operator[](int index) const noexcept
+{
+	auto value = json_array_get(m_handle.get(), index);
+
+	if (value == nullptr)
+		return JsonValue();
+
+	json_incref(value);
+
+	return JsonValue(value);
+}
+
+JsonArray::Ref JsonArray::operator[](int index) noexcept
+{
+	auto value = json_array_get(m_handle.get(), index);
+
+	if (value == nullptr)
+		value = json_null();
+	else
+		json_incref(value);
+
+	return Ref(value, *this, index);
+}
+
+/* --------------------------------------------------------
+ * JsonObject
+ * -------------------------------------------------------- */
+
+JsonObject::Ref JsonObject::operator[](const std::string &name)
+{
+	if (typeOf() != JsonType::Object)
+		return Ref(JsonValue(), *this, name);
+
+	auto value = json_object_get(m_handle.get(), name.c_str());
+
+	json_incref(value);
+
+	return Ref(value, *this, name);
+}
+
+JsonValue JsonObject::operator[](const std::string &name) const
+{
+	if (typeOf() != JsonType::Object)
+		return JsonValue();
+
+	auto value = json_object_get(m_handle.get(), name.c_str());
+
+	if (value == nullptr)
+		return JsonValue();
+
+	json_incref(value);
+
+	return JsonValue(value);
+}
+
+/* --------------------------------------------------------
+ * JsonDocument
+ * -------------------------------------------------------- */
+
+JsonValue JsonDocument::read(std::string content, int flags) const
+{
+	json_error_t error;
+	json_t *json = json_loads(content.c_str(), flags, &error);
+
+	if (json == nullptr)
+		throw JsonError(error);
+
+	return JsonValue(json);
+}
+
+JsonValue JsonDocument::read(std::ifstream &stream, int flags) const
+{
+	if (!stream.is_open())
+		throw JsonError("File not opened");
+
+	stream.seekg(0, stream.end);
+	auto length = stream.tellg();
+	stream.seekg(0, stream.beg);
+
+	std::string buffer;
+	buffer.resize(length, ' ');
+
+	stream.read(&buffer[0], length);
+	stream.close();
+
+	return read(std::move(buffer), flags);
+}
+
+JsonDocument::JsonDocument(std::ifstream &stream, int flags)
+{
+	m_value = read(stream, flags);
+}
+
+JsonDocument::JsonDocument(std::ifstream &&stream, int flags)
+{
+	m_value = read(stream, flags);
+}
+
+JsonDocument::JsonDocument(std::string content, int flags)
+{
+	m_value = read(std::move(content), flags);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Json/Json.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,1603 @@
+/*
+ * Json.h -- jansson C++11 wrapper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _JSON_H_
+#define _JSON_H_
+
+#include <algorithm>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <fstream>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <jansson.h>
+
+/**
+ * @file Json.h
+ * @brief A jansson C++ modern wrapper
+ *
+ * Because of the Jansson implementation, all these classes are implicitly
+ * shared.
+ *
+ * This means that you can't set any value to an existing value as it would
+ * change a value which may be used somewhere else, instead you must set
+ * or replace elements in JsonObject and JsonArray respectively.
+ *
+ * However, copy constructors are implemented as deep copy so take care of
+ * not copying values mistakenly.
+ */
+
+/**
+ * @class JsonType
+ * @brief Json value type
+ */
+enum class JsonType {
+	Object = JSON_OBJECT,		//!< Object
+	Array = JSON_ARRAY,		//!< Array
+	String = JSON_STRING,		//!< String
+	Integer = JSON_INTEGER,		//!< Integer
+	Real = JSON_REAL,		//!< Floating point
+	True = JSON_TRUE,		//!< Boolean true
+	False = JSON_FALSE,		//!< Boolean false
+	Null = JSON_NULL		//!< Empty or null
+};
+
+/**
+ * @class JsonError
+ * @brief Error thrown for any error
+ */
+class JsonError final : public std::exception {
+private:
+	std::string	m_text;
+	std::string	m_source;
+	int		m_line{};
+	int		m_column{};
+	int		m_position{};
+
+public:
+	/**
+	 * Custom error with no line, no column and no position.
+	 *
+	 * @param error the error message
+	 */
+	inline JsonError(std::string error)
+		: m_text(std::move(error))
+	{
+	}
+
+	/**
+	 * Error from a json_error_t.
+	 *
+	 * @param error the error
+	 */
+	inline JsonError(const json_error_t &error)
+		: m_text(error.text)
+		, m_source(error.source)
+		, m_line(error.line)
+		, m_column(error.column)
+		, m_position(error.position)
+	{
+	}
+
+	/**
+	 * Get the error message.
+	 *
+	 * @return the message
+	 */
+	const char *what() const noexcept override
+	{
+		return m_text.c_str();
+	}
+
+	/**
+	 * Get the text message.
+	 *
+	 * @return the text
+	 */
+	inline const std::string &text() const noexcept
+	{
+		return m_text;
+	}
+
+	/**
+	 * Get the source.
+	 *
+	 * @return the source
+	 */
+	inline const std::string &source() const noexcept
+	{
+		return m_source;
+	}
+
+	/**
+	 * Get the line.
+	 *
+	 * @return the line
+	 */
+	inline int line() const noexcept
+	{
+		return m_line;
+	}
+
+	/**
+	 * Get the column.
+	 *
+	 * @return the column
+	 */
+	inline int column() const noexcept
+	{
+		return m_column;
+	}
+
+	/**
+	 * Get the position.
+	 *
+	 * @return the position
+	 */
+	inline int position() const noexcept
+	{
+		return m_position;
+	}
+};
+
+class JsonObject;
+class JsonArray;
+
+/**
+ * @class JsonValue
+ * @brief Encapsulate any JSON value
+ */
+class JsonValue {
+public:
+	using Handle = std::unique_ptr<json_t, void (*)(json_t *)>;
+
+	friend class JsonObject;
+	friend class JsonArray;
+
+protected:
+	/**
+	 * The unique_ptr handle of json_t, will automatically decrease
+	 * the reference count in its deleter.
+	 */
+	Handle m_handle;
+
+	inline void check() const
+	{
+		if (m_handle == nullptr)
+			throw JsonError(std::strerror(errno));
+	}
+
+public:
+	/**
+	 * Deep copy of that element.
+	 *
+	 * @param value the other value
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonValue(const JsonValue &value)
+		: m_handle(json_deep_copy(value.m_handle.get()), json_decref)
+	{
+		check();
+	}
+
+	/**
+	 * Assign a deep copy of the other element.
+	 *
+	 * @return *this
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonValue &operator=(const JsonValue &value)
+	{
+		m_handle = Handle(json_deep_copy(value.m_handle.get()), json_decref);
+
+		check();
+
+		return *this;
+	}
+
+	/**
+	 * Move constructor, the other value is left empty (JsonType::Null).
+	 *
+	 * @param other the other value
+	 */
+	inline JsonValue(JsonValue &&other) noexcept
+		: m_handle(std::move(other.m_handle))
+	{
+		other.m_handle = Handle(json_null(), json_decref);
+	}
+
+	/**
+	 * Move assignment, the other value is left empty (JsonType::Null).
+	 *
+	 * @param other the other value
+	 */
+	inline JsonValue &operator=(JsonValue &&other) noexcept
+	{
+		m_handle = std::move(other.m_handle);
+		other.m_handle = Handle(json_null(), json_decref);
+
+		return *this;
+	}
+
+	/**
+	 * Create a JsonValue from a native Jansson type. This function
+	 * will increment the json_t reference count.
+	 *
+	 * @param json the value
+	 */
+	inline JsonValue(json_t *json) noexcept
+		: m_handle(json, json_decref)
+	{
+	}
+
+	/**
+	 * Construct a null value from a nullptr argument.
+	 */
+	inline JsonValue(std::nullptr_t) noexcept
+		: m_handle(json_null(), json_decref)
+	{
+	}
+
+	/**
+	 * Create an empty value (JsonType::Null).
+	 */
+	inline JsonValue() noexcept
+		: m_handle(json_null(), json_decref)
+	{
+	}
+
+	/**
+	 * Create a boolean value.
+	 *
+	 * @param value the value
+	 */
+	inline JsonValue(bool value) noexcept
+		: m_handle(json_boolean(value), json_decref)
+	{
+	}
+
+	/**
+	 * Create a integer value (JsonType::Integer).
+	 *
+	 * @param value the value
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonValue(int value)
+		: m_handle(json_integer(value), json_decref)
+	{
+		check();
+	}
+
+	/**
+	 * Create a real value (JsonType::Real).
+	 *
+	 * @param value the value
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonValue(double value)
+		: m_handle(json_real(value), json_decref)
+	{
+		check();
+	}
+
+	/**
+	 * Create a string value (JsonType::String).
+	 *
+	 * @param value the value
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonValue(std::string value)
+		: m_handle(json_string(value.c_str()), json_decref)
+	{
+		check();
+	}
+
+	/**
+	 * Create from a C string (JsonType::String).
+	 *
+	 * @param value the string
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonValue(const char *value)
+		: m_handle(json_string(value), json_decref)
+	{
+		check();
+	}
+
+	/**
+	 * Create from a string literal (JsonType::String).
+	 *
+	 * @param value the value
+	 * @throw JsonError on allocation error
+	 */
+	template <size_t Size>
+	inline JsonValue(char (&value)[Size])
+		: m_handle(json_string(value), json_decref)
+	{
+		check();
+	}
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~JsonValue() = default;
+
+	/**
+	 * Get the type of value.
+	 *
+	 * @return the type
+	 */
+	inline JsonType typeOf() const noexcept
+	{
+		return static_cast<JsonType>(json_typeof(m_handle.get()));
+	}
+
+	/**
+	 * Tells if the json value is an JSON_OBJECT.
+	 *
+	 * @return true or false
+	 */
+	inline bool isObject() const noexcept
+	{
+		return json_is_object(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_ARRAY.
+	 *
+	 * @return true or false
+	 */
+	inline bool isArray() const noexcept
+	{
+		return json_is_array(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_STRING.
+	 *
+	 * @return true or false
+	 */
+	inline bool isString() const noexcept
+	{
+		return json_is_string(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_REAL.
+	 *
+	 * @return true or false
+	 */
+	inline bool isReal() const noexcept
+	{
+		return json_is_real(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_TRUE.
+	 *
+	 * @return true or false
+	 */
+	inline bool isTrue() const noexcept
+	{
+		return json_is_true(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_FALSE.
+	 *
+	 * @return true or false
+	 */
+	inline bool isFalse() const noexcept
+	{
+		return json_is_false(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_NULL.
+	 *
+	 * @return true or false
+	 */
+	inline bool isNull() const noexcept
+	{
+		return json_is_null(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_INTEGER or JSON_REAL.
+	 *
+	 * @return true or false
+	 */
+	inline bool isNumber() const noexcept
+	{
+		return json_is_number(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_INTEGER.
+	 *
+	 * @return true or false
+	 */
+	inline bool isInteger() const noexcept
+	{
+		return json_is_integer(m_handle.get());
+	}
+
+	/**
+	 * Tells if the json value is an JSON_TRUE or JSON_FALSE.
+	 *
+	 * @return true or false
+	 */
+	inline bool isBoolean() const noexcept
+	{
+		return json_is_boolean(m_handle.get());
+	}
+
+	/**
+	 * Get the string value.
+	 *
+	 * @return the string
+	 */
+	inline std::string toString() const noexcept
+	{
+		auto value = json_string_value(m_handle.get());
+
+		return (value == nullptr) ? "" : value;
+	}
+
+	/**
+	 * Get the integer value.
+	 *
+	 * @return the value or 0
+	 */
+	inline int toInteger() const noexcept
+	{
+		return json_integer_value(m_handle.get());
+	}
+
+	/**
+	 * Get the real value.
+	 *
+	 * @return the value or 0
+	 */
+	inline double toReal() const noexcept
+	{
+		return json_real_value(m_handle.get());
+	}
+
+	/**
+	 * Convert to object.
+	 *
+	 * @return an object
+	 */
+	JsonObject toObject() const noexcept;
+
+	/**
+	 * Convert to array.
+	 *
+	 * @return an array
+	 */
+	JsonArray toArray() const noexcept;
+
+	/**
+	 * Write to a stream.
+	 *
+	 * @param out the out
+	 * @param flags the optional Jansson flags
+	 */
+	inline void write(std::ofstream &out, int flags = 0) const
+	{
+		auto content = dump(flags);
+
+		std::copy(std::begin(content), std::end(content), std::ostreambuf_iterator<char>(out));
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param out the out
+	 * @param flags the optional Jansson flags
+	 */
+	inline void write(std::ofstream &&out, int flags = 0) const
+	{
+		write(out, flags);
+	}
+
+	/**
+	 * Convert the Json value as a string.
+	 *
+	 * @return the string
+	 * @param flags the optional Jansson flags
+	 */
+	inline std::string dump(int flags = 0) const
+	{
+		auto str = json_dumps(m_handle.get(), flags);
+
+		if (str == nullptr)
+			return "";
+
+		std::string ret(str);
+		std::free(str);
+
+		return ret;
+	}
+
+	/**
+	 * Convert to native Jansson type.
+	 *
+	 * You should not call json_incref or json_decref on it as it is
+	 * automatically done.
+	 *
+	 * @return the json_t handle
+	 * @warning use this function with care
+	 */
+	inline operator json_t *() noexcept
+	{
+		return m_handle.get();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the json_t handle
+	 */
+	inline operator const json_t *() const noexcept
+	{
+		return m_handle.get();
+	}
+
+	/**
+	 * Equality operator.
+	 */
+	inline bool operator==(const JsonValue &other) const noexcept
+	{
+		return json_equal(m_handle.get(), other.m_handle.get());
+	}
+};
+
+/**
+ * @class JsonArray
+ * @brief Manipulate JSON arrays
+ */
+class JsonArray final : public JsonValue {
+public:
+	/**
+	 * @class Ref
+	 * @brief Reference wrapper to be assignable
+	 */
+	class Ref final : public JsonValue {
+	private:
+		JsonArray &m_array;
+		int m_index;
+
+	public:
+		explicit inline Ref(JsonValue value, JsonArray &array, int index)
+			: JsonValue(std::move(value))
+			, m_array(array)
+			, m_index(index)
+		{
+		}
+
+		inline operator JsonValue() const noexcept
+		{
+			return *this;
+		}
+
+		inline JsonValue &operator*() noexcept
+		{
+			return *this;
+		}
+
+		inline JsonValue *operator->() noexcept
+		{
+			return this;
+		}
+
+		inline Ref &operator=(const JsonValue &value)
+		{
+			m_array.replace(value, m_index);
+
+			return *this;
+		}
+
+		inline Ref &operator=(JsonValue &&value)
+		{
+			m_array.replace(std::move(value), m_index);
+
+			return *this;
+		}
+	};
+
+	/**
+	 * @class Ptr
+	 * @brief Pointer wrapper for JsonValue iterators
+	 */
+	class Ptr final : public JsonValue {
+	public:
+		explicit Ptr(JsonValue value) noexcept
+			: JsonValue(std::move(value))
+		{
+		}
+
+		inline JsonValue &operator*() noexcept
+		{
+			return *this;
+		}
+
+		inline JsonValue *operator->() noexcept
+		{
+			return this;
+		}
+	};
+
+	class iterator final {
+	public:
+		using iterator_category = std::random_access_iterator_tag;
+		using difference_type = int;
+		using value_type = JsonValue;
+		using reference = Ref;
+		using pointer = Ptr;
+
+		friend class JsonArray;
+
+	private:
+		JsonArray &m_array;
+		int m_index;
+
+	public:
+		explicit inline iterator(JsonArray &array, int index = 0) noexcept
+			: m_array(array)
+			, m_index(index)
+		{
+		}
+
+		inline Ref operator*() const
+		{
+			return Ref(m_array.at(m_index), m_array, m_index);
+		}
+
+		inline Ptr operator->() const
+		{
+			return Ptr(m_array.at(m_index));
+		}
+
+		inline Ref operator[](int nindex) const noexcept
+		{
+			return Ref(m_array.at(m_index + nindex), m_array, m_index + nindex);
+		}
+
+		inline bool operator==(const iterator &other) const noexcept
+		{
+			return m_index == other.m_index;
+		}
+
+		inline bool operator!=(const iterator &other) const noexcept
+		{
+			return m_index != other.m_index;
+		}
+
+		inline bool operator<(const iterator &other) const noexcept
+		{
+			return m_index < other.m_index;
+		}
+
+		inline bool operator<=(const iterator &other) const noexcept
+		{
+			return m_index <= other.m_index;
+		}
+
+		inline bool operator>(const iterator &other) const noexcept
+		{
+			return m_index > other.m_index;
+		}
+
+		inline bool operator>=(const iterator &other) const noexcept
+		{
+			return m_index >= other.m_index;
+		}
+
+		inline iterator &operator++() noexcept
+		{
+			++m_index;
+
+			return *this;
+		}
+
+		inline iterator operator++(int) noexcept
+		{
+			iterator save = *this;
+
+			++m_index;
+
+			return save;
+		}
+
+		inline iterator &operator--() noexcept
+		{
+			m_index--;
+
+			return *this;
+		}
+
+		inline iterator operator--(int) noexcept
+		{
+			iterator save = *this;
+
+			m_index--;
+
+			return save;
+		}
+
+		inline iterator &operator+=(int nindex) noexcept
+		{
+			m_index += nindex;
+
+			return *this;
+		}
+
+		inline iterator &operator-=(int nindex) noexcept
+		{
+			m_index -= nindex;
+
+			return *this;
+		}
+
+		inline iterator operator+(int nindex) const noexcept
+		{
+			return iterator(m_array, m_index + nindex);
+		}
+
+		inline iterator operator-(int nindex) const noexcept
+		{
+			return iterator(m_array, m_index - nindex);
+		}
+
+		inline int operator-(iterator other) const noexcept
+		{
+			return m_index - other.m_index;
+		}
+	};
+
+	class const_iterator final {
+	public:
+		using iterator_category = std::random_access_iterator_tag;
+		using difference_type = int;
+		using value_type = JsonValue;
+		using reference = JsonValue;
+		using pointer = Ptr;
+
+		friend class JsonArray;
+
+	private:
+		const JsonArray &m_array;
+		int m_index;
+
+	public:
+		explicit inline const_iterator(const JsonArray &array, int index = 0) noexcept
+			: m_array(array)
+			, m_index(index)
+		{
+		}
+
+		inline JsonValue operator*() const
+		{
+			return m_array.at(m_index);
+		}
+
+		inline Ptr operator->() const
+		{
+			return Ptr(m_array.at(m_index));
+		}
+
+		inline JsonValue operator[](int nindex) const noexcept
+		{
+			return m_array.at(m_index + nindex);
+		}
+
+		inline bool operator==(const const_iterator &other) const noexcept
+		{
+			return m_index == other.m_index;
+		}
+
+		inline bool operator!=(const const_iterator &other) const noexcept
+		{
+			return m_index != other.m_index;
+		}
+
+		inline bool operator<(const const_iterator &other) const noexcept
+		{
+			return m_index < other.m_index;
+		}
+
+		inline bool operator<=(const const_iterator &other) const noexcept
+		{
+			return m_index <= other.m_index;
+		}
+
+		inline bool operator>(const const_iterator &other) const noexcept
+		{
+			return m_index > other.m_index;
+		}
+
+		inline bool operator>=(const const_iterator &other) const noexcept
+		{
+			return m_index >= other.m_index;
+		}
+
+		inline const_iterator &operator++() noexcept
+		{
+			++m_index;
+
+			return *this;
+		}
+
+		inline const_iterator operator++(int) noexcept
+		{
+			const_iterator save = *this;
+
+			++m_index;
+
+			return save;
+		}
+
+		inline const_iterator &operator--() noexcept
+		{
+			m_index--;
+
+			return *this;
+		}
+
+		inline const_iterator operator--(int) noexcept
+		{
+			const_iterator save = *this;
+
+			m_index--;
+
+			return save;
+		}
+
+		inline const_iterator &operator+=(int nindex) noexcept
+		{
+			m_index += nindex;
+
+			return *this;
+		}
+
+		inline const_iterator &operator-=(int nindex) noexcept
+		{
+			m_index -= nindex;
+
+			return *this;
+		}
+
+		inline const_iterator operator+(int nindex) const noexcept
+		{
+			return const_iterator(m_array, m_index + nindex);
+		}
+
+		inline const_iterator operator-(int nindex) const noexcept
+		{
+			return const_iterator(m_array, m_index - nindex);
+		}
+
+		inline int operator-(const_iterator other) const noexcept
+		{
+			return m_index - other.m_index;
+		}
+	};
+
+	using size_type = int;
+	using value_type = JsonValue;
+	using const_pointer = const value_type *;
+	using reference = JsonValue &;
+	using const_reference = const JsonValue &;
+	using difference_type = int;
+
+protected:
+	using JsonValue::JsonValue;
+
+public:
+	/**
+	 * Create an empty array.
+	 *
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonArray()
+		: JsonValue(json_array())
+	{
+		check();
+	}
+
+	/**
+	 * Create an array from a list of values.
+	 *
+	 * @param list the list
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonArray(std::initializer_list<value_type> list)
+		: JsonArray()
+	{
+		for (auto &v : list)
+			append(std::move(v));
+	}
+
+	/**
+	 * Returns an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline iterator begin() noexcept
+	{
+		return iterator(*this, 0);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator begin() const noexcept
+	{
+		return const_iterator(*this, 0);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator cbegin() const noexcept
+	{
+		return const_iterator(*this, 0);
+	}
+
+	/**
+	 * Returns an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline iterator end() noexcept
+	{
+		return iterator(*this, size());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator end() const noexcept
+	{
+		return const_iterator(*this, size());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator cend() const noexcept
+	{
+		return const_iterator(*this, size());
+	}
+
+	/**
+	 * Get a value.
+	 *
+	 * @param index the index
+	 * @throw JsonError on error
+	 */
+	JsonValue at(int index) const;
+
+	/**
+	 * Erase the array content.
+	 */
+	inline void clear() noexcept
+	{
+		json_array_clear(m_handle.get());
+	}
+
+	/**
+	 * Remove the element at the specified index.
+	 *
+	 * @param index the index
+	 */
+	inline void erase(int index) noexcept
+	{
+		json_array_remove(m_handle.get(), index);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param it the iterator
+	 */
+	inline void erase(iterator it) noexcept
+	{
+		erase(it.m_index);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param it the iterator
+	 */
+	inline void erase(const_iterator it) noexcept
+	{
+		erase(it.m_index);
+	}
+
+	/**
+	 * Get the number of values in the array
+	 *
+	 * @return the number or 0
+	 */
+	inline unsigned size() const noexcept
+	{
+		return json_array_size(m_handle.get());
+	}
+
+	/**
+	 * Insert the value at the beginning.
+	 *
+	 * @param value the value
+	 */
+	inline void push(const JsonValue &value) noexcept
+	{
+		json_array_insert(m_handle.get(), 0, value.m_handle.get());
+	}
+
+	/**
+	 * Insert a copy of the value at the end.
+	 *
+	 * @param value the value to insert
+	 */
+	inline void append(const JsonValue &value)
+	{
+		json_array_append(m_handle.get(), value.m_handle.get());
+	}
+
+	/**
+	 * Insert a copy of the value at the specified index.
+	 *
+	 * @param value the value to insert
+	 * @param index the position
+	 */
+	inline void insert(const JsonValue &value, int index)
+	{
+		json_array_insert(m_handle.get(), index, value.m_handle.get());
+	}
+
+	/**
+	 * Replace the value at the given index.
+	 *
+	 * @param value the value
+	 * @param index the index
+	 */
+	inline void replace(const JsonValue &value, int index)
+	{
+		json_array_set(m_handle.get(), index, value.m_handle.get());
+	}
+
+	/**
+	 * Get the value at the specified index.
+	 *
+	 * @param index the position
+	 * @return the value
+	 */
+	JsonValue operator[](int index) const noexcept;
+
+	/**
+	 * Access a value as a reference wrapper.
+	 *
+	 * @param index the position
+	 * @return the reference wrapper over the value
+	 */
+	Ref operator[](int index) noexcept;
+};
+
+/**
+ * @class JsonObject
+ * @brief Object wrapper
+ */
+class JsonObject final : public JsonValue {
+public:
+	using key_type = std::string;
+	using mapped_type = JsonValue;
+	using size_type = int;
+	using value_type = std::pair<key_type, mapped_type>;
+	using const_pointer = const value_type *;
+	using reference = JsonValue &;
+	using const_reference = const JsonValue &;
+	using difference_type = int;
+
+	/**
+	 * @class Ref
+	 * @brief Wrapper for updating JsonObject
+	 *
+	 * This class is only used for the following functions:
+	 *
+	 *	JsonObject::operator[]
+	 */
+	class Ref final : public JsonValue {
+	private:
+		JsonObject &m_object;
+		std::string m_key;
+
+	public:
+		explicit inline Ref(JsonValue value, JsonObject &object, std::string key)
+			: JsonValue(std::move(value))
+			, m_object(object)
+			, m_key(std::move(key))
+		{
+		}
+
+		inline operator JsonValue() const noexcept
+		{
+			return *this;
+		}
+
+		inline JsonValue &operator*() noexcept
+		{
+			return *this;
+		}
+
+		inline JsonValue *operator->() noexcept
+		{
+			return this;
+		}
+
+		inline Ref &operator=(const JsonValue &value)
+		{
+			m_object.set(m_key, value);
+
+			return *this;
+		}
+
+		inline Ref &operator=(JsonValue &&value)
+		{
+			m_object.set(m_key, std::move(value));
+
+			return *this;
+		}
+	};
+
+	/**
+	 * @class Ptr
+	 * @brief Pointer wrapper for JsonValue iterators
+	 *
+	 * For const iterators, the real type is a JsonValue, for non const
+	 * iterators it's a ref so that user can edit it.
+	 */
+	template <typename Type>
+	class Ptr final {
+	private:
+		std::pair<std::string, Type> m_pair;
+
+	public:
+		inline Ptr(std::pair<std::string, Type> value) noexcept
+			: m_pair(std::move(value))
+		{
+		}
+
+		inline std::pair<std::string, Type> &operator*() noexcept
+		{
+			return m_pair;
+		}
+
+		inline std::pair<std::string, Type> *operator->() noexcept
+		{
+			return &m_pair;
+		}
+	};
+
+	/**
+	 * @class iterator
+	 * @brief Forward iterator
+	 */
+	class iterator {
+	public:
+		using value_type = std::pair<std::string, Ref>;
+
+		friend class JsonObject;
+
+	private:
+		JsonObject &m_object;
+		void *m_keyIt;
+
+		inline std::string key() const noexcept
+		{
+			return json_object_iter_key(m_keyIt);
+		}
+
+	public:
+		explicit inline iterator(JsonObject &object, void *keyIt) noexcept
+			: m_object(object)
+			, m_keyIt(keyIt)
+		{
+		}
+
+		inline value_type operator*() const
+		{
+			auto k = key();
+
+			return value_type(k, Ref(m_object[k], m_object, k));
+		}
+
+		inline Ptr<Ref> operator->() const
+		{
+			auto k = key();
+
+			return Ptr<Ref>({k, Ref(m_object[k], m_object, k)});
+		}
+
+		inline iterator &operator++() noexcept
+		{
+			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
+
+			return *this;
+		}
+
+		inline iterator operator++(int) noexcept
+		{
+			iterator save = *this;
+
+			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
+
+			return save;
+		}
+
+		inline bool operator==(iterator other) const noexcept
+		{
+			return m_keyIt == other.m_keyIt;
+		}
+
+		inline bool operator!=(iterator other) const noexcept
+		{
+			return m_keyIt != other.m_keyIt;
+		}
+	};
+
+	/**
+	 * @class const_iterator
+	 * @brief Forward iterator
+	 */
+	class const_iterator {
+	public:
+		using value_type = std::pair<std::string, JsonValue>;
+
+		friend class JsonObject;
+
+	private:
+		const JsonObject &m_object;
+		void *m_keyIt;
+
+		inline std::string key() const noexcept
+		{
+			return json_object_iter_key(m_keyIt);
+		}
+
+	public:
+		explicit inline const_iterator(const JsonObject &object, void *keyIt) noexcept
+			: m_object(object)
+			, m_keyIt(keyIt)
+		{
+		}
+
+		inline value_type operator*() const
+		{
+			auto k = key();
+
+			return value_type(k, m_object[k]);
+		}
+
+		inline Ptr<JsonValue> operator->() const
+		{
+			auto k = key();
+
+			return Ptr<JsonValue>({k, m_object[k]});
+		}
+
+		inline const_iterator &operator++() noexcept
+		{
+			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
+
+			return *this;
+		}
+
+		inline const_iterator operator++(int) noexcept
+		{
+			const_iterator save = *this;
+
+			m_keyIt = json_object_iter_next(m_object.m_handle.get(), m_keyIt);
+
+			return save;
+		}
+
+		inline bool operator==(const_iterator other) const noexcept
+		{
+			return m_keyIt == other.m_keyIt;
+		}
+
+		inline bool operator!=(const_iterator other) const noexcept
+		{
+			return m_keyIt != other.m_keyIt;
+		}
+	};
+
+protected:
+	using JsonValue::JsonValue;
+
+public:
+	/**
+	 * Create empty object.
+	 *
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonObject()
+		: JsonValue(json_object())
+	{
+		check();
+	}
+
+	/**
+	 * Create a JsonObject from an initializer_list.
+	 *
+	 * @param list the list of key-value pairs
+	 * @throw JsonError on allocation error
+	 */
+	inline JsonObject(std::initializer_list<value_type> list)
+		: JsonObject()
+	{
+		for (auto &v : list)
+			set(v.first, std::move(v.second));
+	}
+
+	/**
+	 * Returns an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline iterator begin() noexcept
+	{
+		return iterator(*this, json_object_iter(m_handle.get()));
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator begin() const noexcept
+	{
+		return const_iterator(*this, json_object_iter(m_handle.get()));
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator cbegin() const noexcept
+	{
+		return const_iterator(*this, json_object_iter(m_handle.get()));
+	}
+
+	/**
+	 * Returns an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline iterator end() noexcept
+	{
+		return iterator(*this, nullptr);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator end() const noexcept
+	{
+		return const_iterator(*this, nullptr);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator cend() const noexcept
+	{
+		return const_iterator(*this, nullptr);
+	}
+
+	/**
+	 * Check if the object contains a specific property.
+	 *
+	 * @param key the key
+	 * @return true if the object contains the key
+	 */
+	inline bool contains(const std::string &key) const noexcept
+	{
+		return json_object_get(m_handle.get(), key.c_str()) != nullptr;
+	}
+
+	/**
+	 * Get the number of items in the object.
+	 *
+	 * @return the number of items
+	 */
+	inline unsigned size() const noexcept
+	{
+		return json_object_size(m_handle.get());
+	}
+
+	/**
+	 * Remove all elements from the object.
+	 */
+	inline void clear() noexcept
+	{
+		json_object_clear(m_handle.get());
+	}
+
+	/**
+	 * Remove element `key' if exists.
+	 *
+	 * @param key the key
+	 */
+	inline void erase(const std::string &key) noexcept
+	{
+		json_object_del(m_handle.get(), key.c_str());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param it the iterator
+	 */
+	inline void erase(iterator it) noexcept
+	{
+		erase(it.key());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param it the iterator
+	 */
+	inline void erase(const_iterator it) noexcept
+	{
+		erase(it.key());
+	}
+
+	/**
+	 * Set the value as key in the object.
+	 *
+	 * @param key the key
+	 * @param value the value
+	 */
+	inline void set(const std::string &key, const JsonValue &value) noexcept
+	{
+		json_object_set(m_handle.get(), key.c_str(), value.m_handle.get());
+	}
+
+	/**
+	 * Access an object as a wrapper so that you can update its content
+	 * with convenience.
+	 *
+	 * @param key the key
+	 */
+	Ref operator[](const std::string &key);
+
+	/**
+	 * Get the value at the specified key. If the value is not found, an
+	 * empty value is returned
+	 *
+	 * @param key the key
+	 * @return the value
+	 */
+	JsonValue operator[](const std::string &key) const;
+};
+
+/**
+ * @class JsonDocument
+ * @brief Read files and strings to create Json values
+ */
+class JsonDocument final {
+private:
+	JsonValue m_value;
+
+	JsonValue read(std::string, int flags) const;
+	JsonValue read(std::ifstream &stream, int flags) const;
+
+public:
+	/**
+	 * Construct a document from a file.
+	 *
+	 * @param stream the stream
+	 * @param flags the optional Jansson flags
+	 * @throw JsonError on errors
+	 */
+	JsonDocument(std::ifstream &fstream, int flags = 0);
+
+	/**
+	 * Construct a document from a file.
+	 *
+	 * @param stream the stream
+	 * @param flags the optional Jansson flags
+	 * @throw JsonError on errors
+	 */
+	JsonDocument(std::ifstream &&stream, int flags = 0);
+
+	/**
+	 * Construct a document from a file.
+	 *
+	 * @param stream the stream
+	 * @param flags the optional Jansson flags
+	 * @throw JsonError on errors
+	 */
+	JsonDocument(std::string content, int flags = 0);
+
+	/**
+	 * Check if the document contains an object.
+	 *
+	 * @return true if object
+	 */
+	inline bool isObject() const noexcept
+	{
+		return m_value.isObject();
+	}
+
+	/**
+	 * Check if the document contains an array.
+	 *
+	 * @return true if array
+	 */
+	inline bool isArray() const noexcept
+	{
+		return m_value.isArray();
+	}
+
+	/**
+	 * Convert the document value to object
+	 *
+	 * @return the value as object
+	 */
+	inline JsonObject toObject() const noexcept
+	{
+		return m_value.toObject();
+	}
+
+	/**
+	 * Convert the document value to array
+	 *
+	 * @return the value as array
+	 */
+	inline JsonArray toArray() const noexcept
+	{
+		return m_value.toArray();
+	}
+};
+
+#endif // !_JSON_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/OptionParser/OptionParser.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,211 @@
+/*
+ * OptionParser.cpp -- command line option parser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <algorithm>
+
+#include "OptionParser.h"
+
+bool OptionParser::isShort(const std::string &arg) const
+{
+	return arg.size() >= 2 && arg[0] == '-' && arg[1] != '-';
+}
+
+bool OptionParser::isLong(const std::string &arg) const
+{
+	return arg.size() >= 3 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-';
+}
+
+bool OptionParser::isOption(const std::string &arg) const
+{
+	return isShort(arg) || isLong(arg);
+}
+
+std::string OptionParser::key(const std::string &arg) const
+{
+	if (isShort(arg))
+		return arg.substr(1, 1);
+
+	return arg.substr(2);
+}
+
+bool OptionParser::isShortCompacted(const std::string &arg) const
+{
+	return arg.size() >= 3;
+}
+
+bool OptionParser::isDefined(const std::string &arg) const
+{
+	auto n = key(arg);
+	auto it = std::find_if(m_options.begin(), m_options.end(), [&] (const Option &o) -> bool {
+		return o.key() == n || o.full() == n;
+	});
+
+	return it != m_options.end();
+}
+
+const Option &OptionParser::get(const std::string &arg) const
+{
+	std::string n = key(arg);
+
+	return *std::find_if(m_options.begin(), m_options.end(), [&] (const Option &o) -> bool {
+		return o.key() == n || o.full() == n;
+	});
+}
+
+bool OptionParser::isToggle(const std::string &arg) const
+{
+	return (get(arg).flags() & Option::NoArg);
+}
+
+void OptionParser::readShort(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const
+{
+	/*
+	 * There are many options when passing a short option:
+	 *
+	 * 1. -cmyconfig	Takes on argument but parsed as unique,
+	 * 2. -c myconfig	Takes on argument but parsed as two strings
+	 * 3. -abc		If a is not a toggle option, its argument is `bc'
+	 * 4. -abc		If a is a toggle option and b, c are toggle, they are added
+	 */
+
+	std::string v = it->substr(2);
+	std::string k = key(*it);
+	const Option &option = get(std::string("-") + k);
+
+	if (isToggle(*it)) {
+		// 3. and optionally 4.
+		pack.push_back(OptionValue(option, ""));
+		pack.m_argsParsed += 1;
+
+		if (isShortCompacted(*it)) {
+			for (char c : v) {
+				if (!isDefined("-" + std::string(1, c))) {
+					pack.m_error = "-" + std::string(1, c) + " is not a valid option";
+					break;
+				}
+
+				const Option &sub = get("-" + std::string(1, c));
+
+				pack.push_back(OptionValue(sub, ""));
+			}
+		}
+
+		++ it;
+	} else {
+		// 1.
+		if (isShortCompacted(*it++)) {
+			pack.push_back(OptionValue(option, v));
+			pack.m_argsParsed += 1;
+		} else {
+			// 2.
+			if (it == end) {
+				pack.m_error = option.key() + " requires an option";
+			} else {
+				pack.push_back(OptionValue(option, *it++));
+				pack.m_argsParsed += 2;
+			}
+		}
+	}
+}
+
+void OptionParser::readFull(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const
+{
+	/*
+	 * Long options can't be compacted, there are only two possibilities:
+	 *
+	 * 1. --fullscreen	No argument
+	 * 2. --config foo	One argument
+	 */
+	const Option &option = get(*it);
+
+	if (!isToggle(*it)) {
+		// 2.
+		if (++it == end) {
+			pack.m_error = "--" + option.full() + " requires an option";
+		} else {
+			pack.push_back(OptionValue(option, *it++));
+			pack.m_argsParsed += 2;
+		}
+	} else {
+		pack.push_back(OptionValue(option, ""));
+		pack.m_argsParsed ++;
+
+		++ it;
+	}
+}
+
+OptionParser::OptionParser(std::initializer_list<Option> options)
+	: m_options(options.begin(), options.end())
+{
+}
+
+OptionParser::OptionParser(std::vector<Option> options)
+	: m_options(std::move(options))
+{
+}
+
+OptionPack OptionParser::parse(Args::const_iterator it, Args::const_iterator end, int flags) const
+{
+	OptionPack pack;
+
+	while (it != end) {
+		if (!isOption(*it)) {
+			if (flags & Unstrict) {
+				pack.m_argsParsed ++;
+				it ++;
+				continue;
+			} else {
+				pack.m_error = *it + " is not an option";
+				return pack;
+			}
+		}
+
+		if (!isDefined(*it)) {
+			pack.m_error = "Invalid option";
+			return pack;
+		}
+
+		if (isShort(*it)) {
+			readShort(pack, it, end);
+		} else {
+			readFull(pack, it, end);
+		}
+
+		// Read failure
+		if (pack.m_error != "No error") {
+			return pack;
+		}
+	}
+
+	return pack;
+}
+
+OptionPack OptionParser::parse(int argc, char **argv, int flags) const
+{
+	std::vector<std::string> args;
+
+	for (int i = 0; i < argc; ++i)
+		args.push_back(argv[i]);
+
+	return parse(args, flags);
+}
+
+OptionPack OptionParser::parse(const std::vector<std::string> &args, int flags) const
+{
+	return parse(args.begin(), args.end(), flags);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/OptionParser/OptionParser.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,275 @@
+/*
+ * OptionParser.h -- command line option parser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _OPTION_PARSER_H_
+#define _OPTION_PARSER_H_
+
+/**
+ * @file OptionParser.h
+ * @brief Command line option parser
+ */
+
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+/**
+ * @class Option
+ * @brief Option definition
+ */
+class Option {
+public:
+	enum Flags {
+		NoArg	= (1 << 0),
+	};
+
+private:
+	std::string m_key;
+	std::string m_full;
+	int m_flags;
+
+public:
+	/**
+	 * Construct an option. By default, an option requires an argument
+	 * unless flags is set to NoArg.
+	 *
+	 * You <strong>must</strong> not prepend dashes to the option names.
+	 *
+	 * You don't need to set both short and long names, but you need at
+	 * least one.
+	 *
+	 * @param key the short name (e.g v)
+	 * @param full the long name (e.g verbose)
+	 * @param flags the optional flags
+	 * @see Flags
+	 */
+	inline Option(std::string key, std::string full, int flags = 0)
+		: m_key(std::move(key))
+		, m_full(std::move(full))
+		, m_flags(flags)
+	{
+	}
+
+	/**
+	 * Get the short name (e.g v)
+	 *
+	 * @return the short name
+	 */
+	inline const std::string &key() const noexcept
+	{
+		return m_key;
+	}
+
+	/**
+	 * Get the long name (e.g verbose)
+	 *
+	 * @return the long name
+	 */
+	inline const std::string &full() const noexcept
+	{
+		return m_full;
+	}
+
+	/**
+	 * Get the flags.
+	 *
+	 * @return the flags
+	 * @see Flags
+	 */
+	inline int flags() const noexcept
+	{
+		return m_flags;
+	}
+};
+
+/**
+ * @class OptionValue
+ * @brief Result of an option parse
+ */
+class OptionValue {
+private:
+	std::string m_key;
+	std::string m_full;
+	std::string m_value;
+
+public:
+	/**
+	 * Construct an option value
+	 *
+	 * @param option the option
+	 * @param value the value
+	 */
+	inline OptionValue(const Option &option, std::string value)
+		: m_key(option.key())
+		, m_full(option.full())
+		, m_value(std::move(value))
+	{
+	}
+
+	/**
+	 * Get the value (if the option requires an argument).
+	 *
+	 * @return the value
+	 */
+	inline const std::string &value() const noexcept
+	{
+		return m_value;
+	}
+
+	friend bool operator==(const OptionValue &o1, const std::string &name);
+};
+
+/**
+ * Test the option value with the specified option name.
+ *
+ * You can use both the short option or the long option name depending
+ * on what you have registered to the OptionParser class.
+ *
+ * @param o the option
+ * @param name the short or the full name
+ * @return true if matches
+ */
+inline bool operator==(const OptionValue &o, const std::string &name)
+{
+	return o.m_key == name || o.m_full == name;
+}
+
+/**
+ * @class OptionPack
+ * @brief Object containing results of a parse
+ *
+ * Because parsing bad options does not throw exceptions, this class is
+ * convertible to bool and has the error contained.
+ *
+ * It also have the number of arguments parsed so you can cut your options
+ * depending on the full command line.
+ *
+ * Example:
+ *	-y install -d foo
+ *	-y remove -f
+ *
+ * In that case, you can do two parsing, it will stops (unless Unstrict is set)
+ * until install or remove.
+ */
+class OptionPack : public std::vector<OptionValue> {
+private:
+	friend class OptionParser;
+
+	std::string m_error{"No error"};
+	int m_argsParsed{0};
+
+public:
+	/**
+	 * Get the error.
+	 *
+	 * @return the error
+	 */
+	inline const std::string &error() const noexcept
+	{
+		return m_error;
+	}
+
+	/**
+	 * Get the number of arguments parsed <strong>not the number of
+	 * options</strong>.
+	 *
+	 * @return the number of arguments parsed
+	 */
+	inline int parsed() const noexcept
+	{
+		return m_argsParsed;
+	}
+
+	/**
+	 * Convert to true on success.
+	 *
+	 * @return true on success
+	 */
+	inline operator bool() const noexcept
+	{
+		return m_error == "No error";
+	}
+};
+
+/**
+ * @class OptionParser
+ * @brief Base class for parsing command line options
+ *
+ * The option parser is a replacement for getopt(3) which is reentrant
+ * and does not use globals.
+ */
+class OptionParser {
+public:
+	using Map = std::vector<Option>;
+	using Args = std::vector<std::string>;
+
+	enum Flags {
+		Unstrict =	(1 << 0)
+	};
+
+private:
+	Map m_options;
+
+	const Option &get(const std::string &arg) const;
+	std::string key(const std::string &arg) const;
+	bool isDefined(const std::string &arg) const;
+	bool isToggle(const std::string &arg) const;
+	bool isShortCompacted(const std::string &arg) const;
+	bool isShort(const std::string &arg) const;
+	bool isLong(const std::string &arg) const;
+	bool isOption(const std::string &arg) const;
+	void readShort(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const;
+	void readFull(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const;
+	OptionPack parse(Args::const_iterator it, Args::const_iterator end, int flags) const;
+
+public:
+	/**
+	 * Construct an option parser from an initializer_list of options.
+	 *
+	 * @param options the list of options
+	 */
+	OptionParser(std::initializer_list<Option> options);
+
+	/**
+	 * Construct an option parser from a vector of options.
+	 *
+	 * @param options the options
+	 */
+	OptionParser(std::vector<Option> options);
+
+	/**
+	 * Parse the arguments from main arguments.
+	 *
+	 * @param argc the number of arguments
+	 * @param argv the arguments
+	 * @param flags the optional flags
+	 * @return the packed result
+	 */
+	OptionPack parse(int argc, char **argv, int flags = 0) const;
+
+	/**
+	 * Parse the arguments from a vector.
+	 *
+	 * @param args the arguments
+	 * @param flags the optional flags
+	 * @return the packed result
+	 */
+	OptionPack parse(const std::vector<std::string> &args, int flags = 0) const;
+};
+
+#endif // !_OPTION_PARSER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Pack/Pack.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,115 @@
+/*
+ * Pack.cpp -- binary data serialization
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "Pack.h"
+
+namespace {
+
+Pack::Endian checkMode()
+{
+	int i = 1;
+	unsigned char *ptr = reinterpret_cast<unsigned char *>(&i);
+
+	return (ptr[0] == 1) ? Pack::Little : Pack::Big;
+}
+
+} // !namespace
+
+const Pack::Endian Pack::mode = checkMode();
+
+/* --------------------------------------------------------
+ * PackReader
+ * -------------------------------------------------------- */
+
+PackReader::PackReader(Pack::Endian endian)
+	: m_endian(endian)
+{
+}
+
+/* --------------------------------------------------------
+ * PackFileReader
+ * -------------------------------------------------------- */
+
+PackFileReader::PackFileReader(const std::string &path, Pack::Endian endian)
+	: PackReader(endian)
+{
+	m_in.open(path, std::ifstream::in);
+}
+
+std::istream &PackFileReader::stream()
+{
+	return m_in;
+}
+
+/* --------------------------------------------------------
+ * PackStringReader
+ * -------------------------------------------------------- */
+
+PackStringReader::PackStringReader(std::string input, Pack::Endian endian)
+	: PackReader(endian)
+	, m_in(std::move(input))
+{
+}
+
+std::istream &PackStringReader::stream()
+{
+	return m_in;
+}
+
+/* --------------------------------------------------------
+ * PackWriter
+ * -------------------------------------------------------- */
+
+PackWriter::PackWriter(Pack::Endian endian)
+	: m_endian(endian)
+{
+}
+
+/* --------------------------------------------------------
+ * PackFileWriter
+ * -------------------------------------------------------- */
+
+PackFileWriter::PackFileWriter(const std::string &path, Pack::Endian endian)
+	: PackWriter(endian)
+{
+	m_out.open(path, std::ofstream::out);
+}
+
+std::ostream &PackFileWriter::stream()
+{
+	return m_out;
+}
+
+/* --------------------------------------------------------
+ * PackStringWriter
+ * -------------------------------------------------------- */
+
+PackStringWriter::PackStringWriter(Pack::Endian endian)
+	: PackWriter(endian)
+{
+}
+
+std::ostream &PackStringWriter::stream()
+{
+	return m_out;
+}
+
+std::string PackStringWriter::buffer() const
+{
+	return m_out.str();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Pack/Pack.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,408 @@
+/*
+ * Pack.h -- binary data serialization
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PACK_H_
+#define _PACK_H_
+
+#include <cstdint>
+#include <fstream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+/**
+ * @class Pack
+ * @brief Serialize binary data to files
+ *
+ * This class write and read binary data from files. It currently
+ * support:
+ *	uint8_t,
+ *	uint16_t,
+ *	uint32_t,
+ *	uint64_t
+ */
+class Pack {
+private:
+	template <typename T>
+	struct IsContainer {
+		using Yes	= char [1];
+		using No	= char [2];
+
+		template <typename U>
+		static constexpr Yes &test(typename U::value_type *);
+
+		template <typename U>
+		static constexpr No &test(...);
+
+		static constexpr const bool value = sizeof (test<T>(0)) == sizeof (Yes);
+	};
+
+	friend class PackWriter;
+	friend class PackReader;
+
+public:
+	/**
+	 * @enum Endian
+	 * @brief Endian mode
+	 */
+	enum Endian {
+		Little,		//! Little endian
+		Big		//! Big endian
+	};
+
+public:
+	/**
+	 * Host system endian mode.
+	 */
+	static const Endian mode;
+
+	/**
+	 * @struct TypeInfo
+	 * @brief Type information
+	 *
+	 * Used for conversions.
+	 */
+	template <typename T>
+	struct TypeInfo {
+		static constexpr const bool convertible{false};
+		static constexpr const bool serializable{false};
+	};
+
+	/**
+	 * Helper to mark a specialization convertible.
+	 *
+	 * Already done for:
+	 *	uint8_t
+	 *	uint16_t
+	 *	uint32_t
+	 *	uint64_t
+	 *
+	 * The specialization must have the following function:
+	 *
+	 *	static void convert(T &value) noexcept
+	 */
+	struct Convertible {
+		static constexpr const bool convertible{true};
+	};
+
+	/**
+	 * Helper to mark a specialization serializable.
+	 *
+	 * The specialisation must have the following functions:
+	 *
+	 *	static void serialize(PackWriter &writer, const T &)
+	 *	static void unserialize(PackReader &reader, T &)
+	 */
+	struct Serializable {
+		static constexpr const bool serializable{true};
+	};
+
+	/**
+	 * Convert data inplace.
+	 *
+	 * @param value the value
+	 */
+	template <typename T>
+	static inline void convert(T &value) noexcept
+	{
+		static_assert(TypeInfo<T>::convertible, "unsupported type");
+
+		TypeInfo<T>::convert(value);
+	}
+};
+
+/**
+ * @class PackReader
+ * @brief Base abstract reader class
+ */
+class PackReader {
+protected:
+	Pack::Endian m_endian;
+
+	PackReader(Pack::Endian endian);
+
+	virtual std::istream &stream() = 0;
+
+public:
+	/**
+	 * Default destructor.
+	 */
+	virtual ~PackReader() = default;
+
+	/**
+	 * Read a primitive convertible type.
+	 *
+	 * @param value the value destination
+	 * @return *this
+	 */
+	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::convertible>::type * = nullptr>
+	PackReader &operator>>(T &value)
+	{
+		stream().read(reinterpret_cast<char *>(&value), sizeof (T));
+
+		if (m_endian != Pack::mode)
+			Pack::convert(value);
+				
+		return *this;
+	}
+
+	/**
+	 * Read a serializable type.
+	 *
+	 * @param value the value destination
+	 * @return *this
+	 */
+	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::serializable>::type * = nullptr>
+	PackReader &operator>>(T &value)
+	{
+		Pack::TypeInfo<T>::unserialize(*this, value);
+
+		return *this;
+	}
+
+	/**
+	 * Read an array.
+	 *
+	 * This operator is a little bit tricky because you don't  know in
+	 * advance how much data you want to read. Because of that, this
+	 * function looks the capacity of the container and reads that number
+	 * of data.
+	 *
+	 * Because it looks for capacity, you can't use a container which
+	 * already have some data, they will be overriden.
+	 *
+	 * If this is a concern, you should roll your own loop to fill up
+	 * your container.
+	 *
+	 * @param container the container (all previous data will be lost)
+	 * @return *this
+	 */
+	template <typename T, typename std::enable_if<Pack::IsContainer<T>::value>::type * = nullptr>
+	PackReader &operator>>(T &container)
+	{
+		typename T::value_type v;
+
+		T copy;
+
+		for (size_t i = 0; i < container.capacity(); ++i) {
+			(*this) >> v;
+			copy.push_back(v);
+		}
+
+		container = std::move(copy);
+
+		return *this;
+	}
+};
+
+/**
+ * @class PackWriter
+ * @brief Base abstract writer class
+ */
+class PackWriter {
+protected:
+	Pack::Endian m_endian;
+
+	PackWriter(Pack::Endian endian);
+
+	virtual std::ostream &stream() = 0;
+
+public:
+	/**
+	 * Default destructor.
+	 */
+	virtual ~PackWriter() = default;
+
+	/**
+	 * Write a convertible type to the stream.
+	 *
+	 * @param value the value
+	 * @return *this
+	 */
+	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::convertible>::type * = nullptr>
+	PackWriter &operator<<(T value)
+	{
+		if (m_endian != Pack::mode)
+			Pack::convert(value);
+
+		stream().write(reinterpret_cast<const char *>(&value), sizeof (T));
+				
+		return *this;
+	}
+
+	/**
+	 * Write a serializable type to the stream.
+	 *
+	 * @param value the value
+	 * @return *this
+	 */
+	template <typename T, typename std::enable_if<Pack::TypeInfo<T>::serializable>::type * = nullptr>
+	PackWriter &operator<<(const T &value)
+	{
+		Pack::TypeInfo<T>::serialize(*this, value);
+
+		return *this;
+	}
+
+	/**
+	 * Write a container to the stream.
+	 *
+	 * @param container the container
+	 * @return *this
+	 */
+	template <typename T, typename std::enable_if<Pack::IsContainer<T>::value>::type * = nullptr>
+	PackWriter &operator<<(const T &container)
+	{
+		for (const auto &v : container)
+			(*this) << v;
+
+		return *this;
+	}
+};
+
+/**
+ * @class PackFileReader
+ * @brief Extract binary data from a file
+ */
+class PackFileReader : public PackReader {
+private:
+	std::ifstream m_in;
+
+protected:
+	std::istream &stream() override;
+
+public:
+	/**
+	 * Read a file.
+	 *
+	 * @param path the path
+	 * @param endian the endian requested
+	 */
+	PackFileReader(const std::string &path, Pack::Endian endian);
+};
+
+/**
+ * @class PackStringReader
+ * @brief Extract binary data from a string
+ */
+class PackStringReader : public PackReader {
+private:
+	std::istringstream m_in;
+
+	std::istream &stream() override;
+
+public:
+	/**
+	 * Read a string.
+	 *
+	 * @param input the input string
+	 * @param endian the endian requested
+	 */
+	PackStringReader(std::string input, Pack::Endian endian);
+};
+
+/**
+ * @class PackFileWriter
+ * @brief Write binary data to a string
+ */
+class PackFileWriter : public PackWriter {
+private:
+	std::ofstream m_out;
+
+protected:
+	std::ostream &stream() override;
+
+public:
+	/**
+	 * Write to a file.
+	 *
+	 * @param path the path
+	 * @param endian the endian requested
+	 */
+	PackFileWriter(const std::string &path, Pack::Endian endian);
+};
+
+/**
+ * @class PackStringWriter
+ * @brief Write binary data to a string
+ */
+class PackStringWriter : public PackWriter {
+private:
+	std::ostringstream m_out;
+
+	std::ostream &stream() override;
+
+public:
+	/**
+	 * Write to a string
+	 *
+	 * @param endian the endian requested
+	 */
+	PackStringWriter(Pack::Endian endian);
+
+	/**
+	 * The current buffer. Returns a copy of the string.
+	 *
+	 * @return the string
+	 */
+	std::string buffer() const;
+};
+
+template <>
+struct Pack::TypeInfo<uint8_t> : public Pack::Convertible {
+	static inline void convert(uint8_t &) noexcept
+	{
+		// uint8_t are endian independent
+	}
+};
+
+template <>
+struct Pack::TypeInfo<uint16_t> : public Pack::Convertible {
+	static inline void convert(uint16_t &v)
+	{
+		v = (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L));
+	}
+};
+
+template <>
+struct Pack::TypeInfo<uint32_t> : public Pack::Convertible {
+	static inline void convert(uint32_t &v)
+	{
+		v = ((((v) >> 24) & 0x000000FFL)
+		    | (((v) >> 8)  & 0x0000FF00L)
+		    | (((v) << 8)  & 0x00FF0000L)
+		    | (((v) << 24) & 0xFF000000L));
+	}
+};
+
+template <>
+struct Pack::TypeInfo<uint64_t> : public Pack::Convertible {
+	static inline void convert(uint64_t &v)
+	{
+		v = ((((v) & 0xff00000000000000ull) >> 56)
+			| (((v) & 0x00ff000000000000ull) >> 40)
+			| (((v) & 0x0000ff0000000000ull) >> 24)
+			| (((v) & 0x000000ff00000000ull) >> 8 )
+			| (((v) & 0x00000000ff000000ull) << 8 )
+			| (((v) & 0x0000000000ff0000ull) << 24)
+			| (((v) & 0x000000000000ff00ull) << 40)
+			| (((v) & 0x00000000000000ffull) << 56));
+	}
+};
+
+#endif // !_PACK_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Parser/Parser.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,299 @@
+/*
+ * Parser.h -- config file parser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cstring>
+#include <cerrno>
+#include <iostream>
+#include <fstream>
+
+#include "Parser.h"
+
+/* --------------------------------------------------------
+ * Section public members
+ * -------------------------------------------------------- */
+
+Section::Section()
+	: m_allowed(true)
+{
+}
+
+Section::Section(const std::string &name, bool allowed)
+	: m_name(name)
+	, m_allowed(allowed)
+{
+
+}
+
+const std::string &Section::getName() const
+{
+	return m_name;
+}
+
+bool Section::hasOption(const std::string &name) const
+{
+	return m_options.count(name) >= 1;
+}
+
+Section::Map::iterator Section::begin()
+{
+	return m_options.begin();
+}
+
+Section::Map::const_iterator Section::cbegin() const
+{
+	return m_options.cbegin();
+}
+
+Section::Map::iterator Section::end()
+{
+	return m_options.end();
+}
+
+Section::Map::const_iterator Section::cend() const
+{
+	return m_options.end();
+}
+
+bool operator==(const Section &s1, const Section &s2)
+{
+	return s1.m_name == s2.m_name && s1.m_options == s2.m_options;
+}
+
+/* --------------------------------------------------------
+ * Parser private members
+ * -------------------------------------------------------- */
+
+void Parser::addOption(const std::string &key, const std::string &value)
+{
+	m_sections.back().m_options.insert(std::make_pair(key, value));
+}
+
+void Parser::readSection(int lineno, const std::string &line)
+{
+	size_t end;
+
+	if ((end = line.find_first_of(']')) != std::string::npos) {
+		if (end > 1) {
+			auto name = line.substr(1, end - 1);
+
+			/*
+			 * Check if we can add a section, if redefinition is
+			 * disabled, we must disable the previous section so the
+			 * further read options should not be enabled until
+			 * a correct section is found again.
+			 */
+			if (hasSection(name) && (m_tuning & DisableRedefinition)) {
+				if (!(m_tuning & DisableVerbosity))
+					log(lineno, name, "redefinition not allowed");
+				m_sections.back().m_allowed = false;
+			} else {
+				m_sections.push_back(Section(name));
+			}
+		} else if (!(m_tuning & DisableVerbosity)) {
+			/*
+			 * Do not add options at this step because it will
+			 * corrupt the previous one.
+			 */
+			m_sections.back().m_allowed = false;
+			log(lineno, "", "empty section name");
+		}
+	}
+}
+
+void Parser::readOption(int lineno, const std::string &line)
+{
+	auto &current = m_sections.back();
+	size_t epos;
+	std::string key, value;
+
+	// Error on last section?
+	if (!current.m_allowed) {
+		/*
+		 * If it is the root section, this has been probably set by
+		 * DisableRootSection flag, otherwise an error has occured
+		 * so no need to log.
+		 */
+		if (current.m_name == "" && !(m_tuning == DisableVerbosity))
+			log(lineno, "", "option not allowed in that scope");
+
+		return;
+	}
+
+	if ((epos = line.find_first_of('=')) == std::string::npos) {
+		if (!(m_tuning & DisableVerbosity))
+			log(lineno, current.m_name, "missing `=' keyword");
+		return;
+	}
+
+	if (epos > 0) {
+		size_t i, begin, last;
+		char c;
+
+		key = line.substr(0, epos);
+		value = line.substr(epos + 1);
+
+		// clean option key
+		for (i = 0; !isspace(key[i]) && i < key.length(); ++i)
+			continue;
+		key = key.substr(0, i);
+
+		// clean option value
+		for (begin = 0; isspace(value[begin]) && begin < value.length(); ++begin)
+			continue;
+		value = value.substr(begin);
+	
+		c = value[0];
+		begin = 0;
+		if (c == '\'' || c == '"') {
+			for (last = begin = 1; value[last] != c && last < value.length(); ++last)
+				continue;
+			if (value[last] != c && !(m_tuning & DisableVerbosity))
+				if (!(m_tuning & DisableVerbosity))
+					log(lineno, current.m_name, "undisclosed std::string");
+		} else {
+			for (last = begin; !isspace(value[last]) && last < value.length(); ++last)
+				continue;
+		}
+
+		if (last - begin > 0)
+			value = value.substr(begin, last - begin);
+		else
+			value.clear();
+
+		// Add the option if the key is not empty
+		if (key.length() > 0)
+			addOption(key, value);
+	}
+}
+
+void Parser::readLine(int lineno, const std::string &line)
+{
+	size_t i;
+	std::string buffer;
+
+	// Skip default spaces
+	for (i = 0; isspace(line[i]) && i < line.length(); ++i)
+		continue;
+
+	buffer = line.substr(i);
+	if (buffer.length() > 0) {
+		if (buffer[0] != m_commentChar) {
+			if (buffer[0] == '[')
+				readSection(lineno, buffer);
+			else
+				readOption(lineno, buffer);
+		}
+	}
+}
+
+/* --------------------------------------------------------
+ * Parser public methods
+ * -------------------------------------------------------- */
+
+const char Parser::DEFAULT_COMMENT_CHAR = '#';
+
+void Parser::open()
+{
+	std::ifstream file;
+	std::string line;
+	int lineno = 1;
+
+	file.open(m_path.c_str());
+	if (!file.is_open())
+		throw std::runtime_error(m_path + ": " + std::string(std::strerror(errno)));
+
+	while (std::getline(file, line))
+		readLine(lineno++, line);
+
+	file.close();
+}
+
+Parser::Parser()
+{
+}
+
+Parser::Parser(const std::string &path, int tuning, char commentToken)
+	: m_path(path)
+	, m_tuning(tuning)
+	, m_commentChar(commentToken)
+{
+	m_sections.push_back(Section("", (tuning & DisableRootSection) ? false : true));
+	open();
+}
+
+Parser::~Parser()
+{
+}
+
+Parser::List::iterator Parser::begin()
+{
+	return m_sections.begin();
+}
+
+Parser::List::const_iterator Parser::cbegin() const
+{
+	return m_sections.cbegin();
+}
+
+Parser::List::iterator Parser::end()
+{
+	return m_sections.end();
+}
+
+Parser::List::const_iterator Parser::cend() const
+{
+	return m_sections.end();
+}
+
+void Parser::findSections(const std::string &name, FindFunc func) const
+{
+	for (const auto &s : m_sections)
+		if (s.m_name == name)
+			func(s);
+}
+
+bool Parser::hasSection(const std::string &name) const
+{
+	for (const auto &s : m_sections)
+		if (s.m_name == name)
+			return true;
+
+	return false;
+}
+
+const Section &Parser::getSection(const std::string &name) const
+{
+	for (const auto &s : m_sections)
+		if (s.m_name == name)
+			return s;
+
+	throw std::out_of_range(name + " not found");
+}
+
+void Parser::log(int number, const std::string &, const std::string &message)
+{
+	std::cout << "line " << number << ": " << message << std::endl;
+}
+
+bool operator==(const Parser &p1, const Parser &p2)
+{
+	return p1.m_sections == p2.m_sections &&
+	    p1.m_path == p2.m_path &&
+	    p1.m_tuning == p2.m_tuning &&
+	    p1.m_commentChar == p2.m_commentChar;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Parser/Parser.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,336 @@
+/*
+ * Parser.h -- config file parser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PARSER_H_
+#define _PARSER_H_
+
+#include <cstdlib>
+#include <functional>
+#include <stdexcept>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+/**
+ * @class Section
+ * @brief The option container
+ *
+ * A list of section found in the file. If root
+ * options are allowed (default behavior), the root
+ * section is "".
+ */
+class Section {
+public:
+	friend class Parser;
+
+	using Map = std::unordered_map<std::string, std::string>;
+
+	template <typename T>
+	struct Converter {
+		static const bool supported = false;
+	};
+
+private:
+	std::string	m_name;		/*! name of section */
+	Map		m_options;	/*! list of options inside */
+	bool		m_allowed;	/*! is authorized to push */
+
+public:
+	/**
+	 * Default constructor.
+	 */
+	Section();
+
+	/**
+	 * Named constructor.
+	 *
+	 * @param name the section name
+	 * @param allowed is allowed to push
+	 */
+	Section(const std::string &name, bool allowed = true);
+
+	/**
+	 * Tells if that section has the specified option name.
+	 *
+	 * @param name the option name
+	 * @return true if has
+	 */
+	bool hasOption(const std::string &name) const;
+
+	/**
+	 * Get the section name
+	 *
+	 * @return the section name
+	 */
+	const std::string &getName() const;
+
+	/**
+	 * Return an iterator to the beginning.
+	 *
+	 * @return the iterator.
+	 */
+	Map::iterator begin();
+
+	/**
+	 * Return a const iterator to the beginning.
+	 *
+	 * @return the iterator.
+	 */
+	Map::const_iterator cbegin() const;
+
+	/**
+	 * Return an iterator to the end.
+	 *
+	 * @return the iterator.
+	 */
+	Map::iterator end();
+	
+	/**
+	 * Return a const iterator to the end.
+	 *
+	 * @return the iterator.
+	 */
+	Map::const_iterator cend() const;
+
+	/**
+	 * Template all functions for retrieving options value.
+	 *
+	 * @param name the option name
+	 * @return the value if found
+	 */
+	template <typename T>
+	T getOption(const std::string &name) const
+	{
+		try {
+			return requireOption<T>(name);
+		} catch (...) {
+			// Catch any conversion error.
+		}
+
+		return T();
+	}
+
+	/**
+	 * Requires an option, this works like getOption except
+	 * that if an option is not found, an exception is
+	 * thrown.
+	 *
+	 * @param name the name
+	 * @return the value
+	 * @throw std::out_of_range if not found
+	 * @throw std::invalid_argument on conversion failures
+	 */
+	template <typename T>
+	T requireOption(const std::string &name) const
+	{
+		static_assert(Converter<T>::supported, "invalid type requested");
+
+		return Converter<T>::convert(m_options.at(name));
+	}
+
+	friend bool operator==(const Section &s1, const Section &s2);
+};
+
+template <>
+struct Section::Converter<bool> {
+	static const bool supported = true;
+
+	static bool convert(const std::string &value)
+	{
+		bool result(false);
+
+		if (value == "yes" || value == "true"|| value == "1")
+			result = true;
+		else if (value == "no" || value == "false" || value == "0")
+			result = false;
+
+		return result;
+	}
+};
+
+template <>
+struct Section::Converter<int> {
+	static const bool supported = true;
+
+	static int convert(const std::string &value)
+	{
+		return std::stoi(value);
+	}
+};
+
+template <>
+struct Section::Converter<float> {
+	static const bool supported = true;
+
+	static float convert(const std::string &value)
+	{
+		return std::stof(value);
+	}
+};
+
+template <>
+struct Section::Converter<double> {
+	static const bool supported = true;
+
+	static double convert(const std::string &value)
+	{
+		return std::stod(value);
+	}
+};
+
+template <>
+struct Section::Converter<std::string> {
+	static const bool supported = true;
+
+	static std::string convert(const std::string &value)
+	{
+		return value;
+	}
+};
+
+/**
+ * @class Parser
+ * @brief Config file parser
+ *
+ * Open and read .ini files.
+ */
+class Parser {
+public:
+	/**
+	 * Options available for the parser.
+	 */
+	enum Tuning {
+		DisableRootSection	= 1,	/*! disable options on root */
+		DisableRedefinition	= 2,	/*! disable multiple redefinition */
+		DisableVerbosity	= 4	/*! be verbose by method */
+	};
+
+	using FindFunc	= std::function<void (const Section &)>;
+	using List	= std::vector<Section>;
+
+private:
+	List		m_sections;		/*! list of sections found */
+	std::string	m_path;			/*! path file */
+	int		m_tuning;		/*! options for parsing */
+	char		m_commentChar;		/*! the comment token default (#) */
+
+	void addSection(const std::string &name);
+	void addOption(const std::string &key, const std::string &value);
+
+	void readSection(int lineno, const std::string &line);
+	void readOption(int lineno, const std::string &line);
+
+	void readLine(int lineno, const std::string &line);
+
+	void open();
+
+public:
+	static const char DEFAULT_COMMENT_CHAR;
+
+	/**
+	 * Create a parser at the specified file path. Optional
+	 * options may be added.
+	 *
+	 * @param path the file path
+	 * @param tuning optional tuning flags
+	 * @param commentToken an optional comment delimiter
+	 * @throw std::runtime_error on errors
+	 * @see Tuning
+	 */
+	Parser(const std::string &path, int tuning = 0, char commentToken = Parser::DEFAULT_COMMENT_CHAR);
+
+	/**
+	 * Default constructor.
+	 */
+	Parser();
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~Parser();
+
+	/**
+	 * Return an iterator to the beginning.
+	 *
+	 * @return the iterator.
+	 */
+	List::iterator begin();
+
+	/**
+	 * Return a const iterator to the beginning.
+	 *
+	 * @return the iterator.
+	 */
+	List::const_iterator cbegin() const;
+
+	/**
+	 * Return an iterator to the end.
+	 *
+	 * @return the iterator.
+	 */
+	List::iterator end();
+	
+	/**
+	 * Return a const iterator to the end.
+	 *
+	 * @return the iterator.
+	 */
+	List::const_iterator cend() const;
+
+	/**
+	 * Find all sections matching the name.
+	 *
+	 * @param name the sections name
+	 * @param func the function 
+	 * @return a list of section with the options
+	 */
+	void findSections(const std::string &name, FindFunc func) const;
+
+	/**
+	 * Tell if a section is existing.
+	 *
+	 * @return true if exists
+	 */
+	bool hasSection(const std::string &name) const;
+
+	/**
+	 * Get a specified section.
+	 *
+	 * @param name the section name
+	 * @return a section
+	 * @throw std::out_of_range if not found
+	 */
+	const Section &getSection(const std::string &name) const;
+
+	/**
+	 * Logging function, used only if DisableVerbosity is not set. The
+	 * default behavior is to print to stdout something like:
+	 * line 10: syntax error
+	 * line 8: missing =
+	 *
+	 * @param number the line number
+	 * @param section the current section worked on
+	 * @param message the message
+	 */
+	virtual void log(int number, const std::string &section, const std::string &message);
+
+	friend bool operator==(const Parser &p1, const Parser &p2);
+};
+
+#endif // !_PARSER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/Socket.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,173 @@
+/*
+ * Socket.cpp -- portable C++ socket wrappers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cstring>
+
+#include "Socket.h"
+#include "SocketAddress.h"
+
+/* --------------------------------------------------------
+ * System dependent code
+ * -------------------------------------------------------- */
+
+#if defined(_WIN32)
+
+std::string Socket::syserror(int errn)
+{
+	LPSTR str = nullptr;
+	std::string errmsg = "Unknown error";
+
+	FormatMessageA(
+		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL,
+		errn,
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		(LPSTR)&str, 0, NULL);
+
+
+	if (str) {
+		errmsg = std::string(str);
+		LocalFree(str);
+	}
+
+	return errmsg;
+}
+
+#else
+
+#include <cerrno>
+
+std::string Socket::syserror(int errn)
+{
+	return strerror(errn);
+}
+
+#endif
+
+std::string Socket::syserror()
+{
+#if defined(_WIN32)
+	return syserror(WSAGetLastError());
+#else
+	return syserror(errno);
+#endif
+}
+
+/* --------------------------------------------------------
+ * SocketError class
+ * -------------------------------------------------------- */
+
+SocketError::SocketError(Code code, std::string function)
+	: m_code(code)
+	, m_function(std::move(function))
+	, m_error(Socket::syserror())
+{
+}
+
+SocketError::SocketError(Code code, std::string function, int error)
+	: m_code(code)
+	, m_function(std::move(function))
+	, m_error(Socket::syserror(error))
+{
+}
+
+SocketError::SocketError(Code code, std::string function, std::string error)
+	: m_code(code)
+	, m_function(std::move(function))
+	, m_error(std::move(error))
+{
+}
+
+/* --------------------------------------------------------
+ * Socket class
+ * -------------------------------------------------------- */
+
+#if defined(_WIN32)
+std::mutex Socket::s_mutex;
+std::atomic<bool> Socket::s_initialized{false};
+#endif
+
+Socket::Socket(int domain, int type, int protocol)
+{
+#if defined(_WIN32) && !defined(SOCKET_NO_WSA_INIT)
+	if (!s_initialized)
+		initialize();
+#endif
+
+	m_handle = ::socket(domain, type, protocol);
+
+	if (m_handle == Invalid)
+		throw SocketError(SocketError::System, "socket");
+
+	m_state = SocketState::Opened;
+}
+
+void Socket::bind(const SocketAddress &address)
+{
+	const auto &sa = address.address();
+	const auto addrlen = address.length();
+
+	if (::bind(m_handle, reinterpret_cast<const sockaddr *>(&sa), addrlen) == Error)
+		throw SocketError(SocketError::System, "bind");
+
+	m_state = SocketState::Bound;
+}
+
+void Socket::close()
+{
+#if defined(_WIN32)
+	::closesocket(m_handle);
+#else
+	::close(m_handle);
+#endif
+
+	m_state = SocketState::Closed;
+}
+
+void Socket::setBlockMode(bool block)
+{
+#if defined(O_NONBLOCK) && !defined(_WIN32)
+	int flags;
+
+	if ((flags = fcntl(m_handle, F_GETFL, 0)) == -1)
+		flags = 0;
+
+	if (block)
+		flags &= ~(O_NONBLOCK);
+	else
+		flags |= O_NONBLOCK;
+
+	if (fcntl(m_handle, F_SETFL, flags) == Error)
+		throw SocketError(SocketError::System, "setBlockMode");
+#else
+	unsigned long flags = (block) ? 0 : 1;
+
+	if (ioctlsocket(m_handle, FIONBIO, &flags) == Error)
+		throw SocketError(SocketError::System, "setBlockMode");
+#endif
+}
+
+bool operator==(const Socket &s1, const Socket &s2)
+{
+	return s1.handle() == s2.handle();
+}
+
+bool operator<(const Socket &s1, const Socket &s2)
+{
+	return s1.handle() < s2.handle();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/Socket.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,404 @@
+/*
+ * Socket.h -- portable C++ socket wrappers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SOCKET_NG_H_
+#define _SOCKET_NG_H_
+
+/**
+ * @file Socket.h
+ * @brief Portable socket abstraction
+ *
+ * User may set the following variables before compiling these files:
+ *
+ * SOCKET_NO_WSA_INIT	- (bool) Set to false if you don't want Socket class to
+ *			  automatically calls WSAStartup() when creating sockets.
+ *
+ *			  Otherwise, you will need to call Socket::init,
+ *			  Socket::finish yourself.
+ *
+ * SOCKET_NO_SSL_INIT	- (bool) Set to false if you don't want OpenSSL to be
+ *			  initialized when the first SocketSsl object is created.
+ *
+ * SOCKET_HAVE_POLL	- (bool) Set to true if poll(2) function is available.
+ *
+ *			  Note: on Windows, this is automatically set if the
+ *			  _WIN32_WINNT variable is greater or equal to 0x0600.
+ */
+
+#include <cstring>
+#include <exception>
+#include <string>
+
+#if defined(_WIN32)
+#  include <atomic>
+#  include <cstdlib>
+#  include <mutex>
+
+#  include <WinSock2.h>
+#  include <WS2tcpip.h>
+#else
+#  include <cerrno>
+
+#  include <sys/ioctl.h>
+#  include <sys/socket.h>
+#  include <sys/types.h>
+
+#  include <arpa/inet.h>
+
+#  include <netinet/in.h>
+
+#  include <fcntl.h>
+#  include <netdb.h>
+#  include <unistd.h>
+#endif
+
+class SocketAddress;
+
+/**
+ * @class SocketError
+ * @brief Base class for sockets error
+ */
+class SocketError : public std::exception {
+public:
+	enum Code {
+		WouldBlockRead,		///!< The operation would block for reading
+		WouldBlockWrite,	///!< The operation would block for writing
+		Timeout,		///!< The action did timeout
+		System			///!< There is a system error
+	};
+
+	Code m_code;
+	std::string m_function;
+	std::string m_error;
+
+	/**
+	 * Constructor that use the last system error.
+	 *
+	 * @param code which kind of error
+	 * @param function the function name
+	 */
+	SocketError(Code code, std::string function);
+
+	/**
+	 * Constructor that use the system error set by the user.
+	 *
+	 * @param code which kind of error
+	 * @param function the function name
+	 * @param error the error
+	 */
+	SocketError(Code code, std::string function, int error);
+
+	/**
+	 * Constructor that set the error specified by the user.
+	 *
+	 * @param code which kind of error
+	 * @param function the function name
+	 * @param error the error
+	 */
+	SocketError(Code code, std::string function, std::string error);
+
+	/**
+	 * Get which function has triggered the error.
+	 *
+	 * @return the function name (e.g connect)
+	 */
+	inline const std::string &function() const noexcept
+	{
+		return m_function;
+	}
+
+	/**
+	 * The error code.
+	 *
+	 * @return the code
+	 */
+	inline Code code() const noexcept
+	{
+		return m_code;
+	}
+
+	/**
+	 * Get the error (only the error content).
+	 *
+	 * @return the error
+	 */
+	const char *what() const noexcept
+	{
+		return m_error.c_str();
+	}
+};
+
+/**
+ * @enum SocketState
+ * @brief Category of error
+ */
+enum class SocketState {
+	Opened,				///!< Socket is opened
+	Closed,				///!< Socket has been closed
+	Bound,				///!< Socket is bound to address
+	Connected,			///!< Socket is connected to an end point
+	Disconnected,			///!< Socket is disconnected
+	Timeout				///!< Timeout has occured in a waiting operation
+};
+
+/**
+ * @class Socket
+ * @brief Base socket class for socket operations
+ */
+class Socket {
+public:
+	/* {{{ Portable types */
+
+	/*
+	 * The following types are defined differently between Unix
+	 * and Windows.
+	 */
+#if defined(_WIN32)
+	using Handle	= SOCKET;
+	using ConstArg	= const char *;
+	using Arg	= char *;
+#else
+	using Handle	= int;
+	using ConstArg	= const void *;
+	using Arg	= void *;
+#endif
+
+	/* }}} */
+
+	/* {{{ Portable constants */
+
+	/*
+	 * The following constants are defined differently from Unix
+	 * to Windows.
+	 */
+#if defined(_WIN32)
+	static constexpr const int Invalid	= INVALID_SOCKET;
+	static constexpr const int Error	= SOCKET_ERROR;
+#else
+	static constexpr const int Invalid	= -1;
+	static constexpr const int Error	= -1;
+#endif
+
+	/* }}} */
+
+	/* {{{ Portable initialization */
+
+	/*
+	 * Initialization stuff.
+	 *
+	 * The function init and finish are threadsafe.
+	 */
+#if defined(_WIN32)
+private:
+	static std::mutex s_mutex;
+	static std::atomic<bool> s_initialized;
+
+public:
+	static inline void finish() noexcept
+	{
+		WSACleanup();
+	}
+
+	static inline void init() noexcept
+	{
+		std::lock_guard<std::mutex> lock(s_mutex);
+
+		if (!s_initialized) {
+			s_initialized = true;
+
+			WSADATA wsa;
+			WSAStartup(MAKEWORD(2, 2), &wsa);
+
+			/*
+			 * If SOCKET_WSA_NO_INIT is not set then the user
+			 * must also call finish himself.
+			 */
+#if !defined(SOCKET_WSA_NO_INIT)
+			std::atexit(finish);
+#endif
+		}
+	}
+#else
+public:
+	/**
+	 * no-op.
+	 */
+	static inline void init() noexcept {}
+
+	/**
+	 * no-op.
+	 */
+	static inline void finish() noexcept {}
+#endif
+
+	/* }}} */
+
+protected:
+	Handle m_handle;
+	SocketState m_state{SocketState::Opened};
+
+public:
+	/**
+	 * Get the last socket system error. The error is set from errno or from
+	 * WSAGetLastError on Windows.
+	 *
+	 * @return a string message
+	 */
+	static std::string syserror();
+
+	/**
+	 * Get the last system error.
+	 *
+	 * @param errn the error number (errno or WSAGetLastError)
+	 * @return the error
+	 */
+	static std::string syserror(int errn);
+
+	/**
+	 * Construct a socket with an already created descriptor.
+	 *
+	 * @param handle the native descriptor
+	 */
+	inline Socket(Handle handle)
+		: m_handle(handle)
+		, m_state(SocketState::Opened)
+	{
+	}
+
+	/**
+	 * Create a socket handle.
+	 *
+	 * @param domain the domain AF_*
+	 * @param type the type SOCK_*
+	 * @param protocol the protocol
+	 * @throw SocketError on failures
+	 */
+	Socket(int domain, int type, int protocol);
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~Socket() = default;
+
+	/**
+	 * Set an option for the socket.
+	 *
+	 * @param level the setting level
+	 * @param name the name
+	 * @param arg the value
+	 * @throw SocketError on error
+	 */
+	template <typename Argument>
+	inline void set(int level, int name, const Argument &arg)
+	{
+#if defined(_WIN32)
+		if (setsockopt(m_handle, level, name, (Socket::ConstArg)&arg, sizeof (arg)) == SOCKET_ERROR)
+#else
+		if (setsockopt(m_handle, level, name, (Socket::ConstArg)&arg, sizeof (arg)) < 0)
+#endif
+			throw SocketError(SocketError::System, "set");
+	}
+
+	/**
+	 * Get an option for the socket.
+	 *
+	 * @param level the setting level
+	 * @param name the name
+	 * @throw SocketError on error
+	 */
+	template <typename Argument>
+	inline Argument get(int level, int name)
+	{
+		Argument desired, result{};
+		socklen_t size = sizeof (result);
+
+#if defined(_WIN32)
+		if (getsockopt(m_handle, level, name, (Socket::Arg)&desired, &size) == SOCKET_ERROR)
+#else
+		if (getsockopt(m_handle, level, name, (Socket::Arg)&desired, &size) < 0)
+#endif
+			throw SocketError(SocketError::System, "get");
+
+		std::memcpy(&result, &desired, size);
+
+		return result;
+	}
+
+	/**
+	 * Get the native handle.
+	 *
+	 * @return the handle
+	 * @warning Not portable
+	 */
+	inline Handle handle() const noexcept
+	{
+		return m_handle;
+	}
+
+	/**
+	 * Get the socket state.
+	 *
+	 * @return
+	 */
+	inline SocketState state() const noexcept
+	{
+		return m_state;
+	}
+
+	/**
+	 * Bind to an address.
+	 *
+	 * @param address the address
+	 * @throw SocketError on any error
+	 */
+	void bind(const SocketAddress &address);
+
+	/**
+	 * Set the blocking mode, if set to false, the socket will be marked
+	 * **non-blocking**.
+	 *
+	 * @param block set to false to mark **non-blocking**
+	 * @throw SocketError on any error
+	 */
+	void setBlockMode(bool block);
+
+	/**
+	 * Close the socket.
+	 */
+	virtual void close();
+};
+
+/**
+ * Compare two sockets.
+ *
+ * @param s1 the first socket
+ * @param s2 the second socket
+ * @return true if they equals
+ */
+bool operator==(const Socket &s1, const Socket &s2);
+
+/**
+ * Compare two sockets, ideal for putting in a std::map.
+ *
+ * @param s1 the first socket
+ * @param s2 the second socket
+ * @return true if s1 < s2
+ */
+bool operator<(const Socket &s1, const Socket &s2);
+
+#endif // !_SOCKET_NG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketAddress.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,136 @@
+/*
+ * SocketAddress.cpp -- socket addresses management
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <algorithm>
+#include <cstring>
+
+#include "Socket.h"
+#include "SocketAddress.h"
+
+namespace address {
+
+/* --------------------------------------------------------
+ * Internet implementation
+ * -------------------------------------------------------- */
+
+Internet::Internet(const std::string &host, unsigned port, int domain)
+{
+	if (host == "*") {
+		if (domain == AF_INET6) {
+			sockaddr_in6 *ptr = (sockaddr_in6 *)&m_addr;
+
+			ptr->sin6_addr = in6addr_any;
+			ptr->sin6_family = AF_INET6;
+			ptr->sin6_port = htons(port);
+
+			m_addrlen = sizeof (sockaddr_in6);
+		} else {
+			sockaddr_in *ptr = (sockaddr_in *)&m_addr;
+
+			ptr->sin_addr.s_addr = INADDR_ANY;
+			ptr->sin_family = AF_INET;
+			ptr->sin_port = htons(port);
+
+			m_addrlen = sizeof (sockaddr_in);
+		}
+	} else {
+		addrinfo hints, *res;
+
+		std::memset(&hints, 0, sizeof (addrinfo));
+		hints.ai_family = domain;
+
+		auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);
+		if (error != 0)
+			throw SocketError(SocketError::System, "getaddrinfo", gai_strerror(error));
+
+		std::memcpy(&m_addr, res->ai_addr, res->ai_addrlen);
+		m_addrlen = res->ai_addrlen;
+		freeaddrinfo(res);
+	}
+}
+
+/* --------------------------------------------------------
+ * Unix implementation
+ * -------------------------------------------------------- */
+
+#if !defined(_WIN32)
+
+#include <sys/un.h>
+
+Unix::Unix(const std::string &path, bool rm)
+{
+	sockaddr_un *sun = (sockaddr_un *)&m_addr;
+
+	// Silently remove the file even if it fails
+	if (rm)
+		::remove(path.c_str());
+
+	// Copy the path
+	memset(sun->sun_path, 0, sizeof (sun->sun_path));
+	strncpy(sun->sun_path, path.c_str(), sizeof (sun->sun_path) - 1);
+
+	// Set the parameters
+	sun->sun_family = AF_UNIX;
+	m_addrlen = SUN_LEN(sun);
+}
+
+#endif // _WIN32
+
+} // !address
+
+/* --------------------------------------------------------
+ * SocketAddress implementation
+ * -------------------------------------------------------- */
+
+SocketAddress::SocketAddress()
+	: m_addrlen(0)
+{
+	memset(&m_addr, 0, sizeof (m_addr));
+}
+
+SocketAddress::SocketAddress(const sockaddr_storage &addr, socklen_t length)
+	: m_addr(addr)
+	, m_addrlen(length)
+{
+}
+
+const sockaddr_storage &SocketAddress::address() const
+{
+	return m_addr;
+}
+
+socklen_t SocketAddress::length() const
+{
+	return m_addrlen;
+}
+
+bool operator<(const SocketAddress &s1, const SocketAddress &s2)
+{
+	const auto &array1 = reinterpret_cast<const unsigned char *>(&s1.address());
+	const auto &array2 = reinterpret_cast<const unsigned char *>(&s2.address());
+
+	return std::lexicographical_compare(array1, array1 + s1.length(), array2, array2 + s2.length());
+}
+
+bool operator==(const SocketAddress &s1, const SocketAddress &s2)
+{
+	const auto &array1 = reinterpret_cast<const unsigned char *>(&s1.address());
+	const auto &array2 = reinterpret_cast<const unsigned char *>(&s2.address());
+
+	return std::equal(array1, array1 + s1.length(), array2, array2 + s2.length());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketAddress.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,143 @@
+/*
+ * SocketAddress.h -- socket addresses management
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SOCKET_ADDRESS_NG_H_
+#define _SOCKET_ADDRESS_NG_H_
+
+#include <string>
+
+#if defined(_WIN32)
+#  include <Winsock2.h>
+#  include <Ws2tcpip.h>
+#else
+#  include <sys/socket.h>
+#endif
+
+/**
+ * @class SocketAddress
+ * @brief base class for socket addresses
+ *
+ * This class is mostly used to bind, connect or getting information
+ * on socket clients.
+ *
+ * @see Internet
+ * @see Unix
+ */
+class SocketAddress {
+protected:
+	sockaddr_storage m_addr;
+	socklen_t m_addrlen;
+
+public:
+	/**
+	 * Default constructor.
+	 */
+	SocketAddress();
+
+	/**
+	 * Constructor with address and size.
+	 *
+	 * @param addr the address
+	 * @param length the address length
+	 */
+	SocketAddress(const sockaddr_storage &addr, socklen_t length);
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~SocketAddress() = default;
+
+	/**
+	 * Get the address length
+	 *
+	 * @return the length
+	 */
+	socklen_t length() const;
+
+	/**
+	 * Get the address.
+	 *
+	 * @return the address
+	 */
+	const sockaddr_storage &address() const;
+
+	/**
+	 * Compare the addresses. The check is lexicographical.
+	 *
+	 * @param s1 the first address
+	 * @param s2 the second address
+	 * @return true if s1 is less than s2
+	 */
+	friend bool operator<(const SocketAddress &s1, const SocketAddress &s2);
+
+	/**
+	 * Compare the addresses.
+	 *
+	 * @param s1 the first address
+	 * @param s2 the second address
+	 * @return true if s1 == s2
+	 */
+	friend bool operator==(const SocketAddress &s1, const SocketAddress &s2);
+};
+
+namespace address {
+
+/**
+ * @class Internet
+ * @brief internet protocol connect class
+ *
+ * Create a connect address for internet protocol,
+ * using getaddrinfo(3).
+ */
+class Internet : public SocketAddress {
+public:
+	/**
+	 * Create an IPv4 or IPV6 end point.
+	 *
+	 * @param host the hostname
+	 * @param port the port
+	 * @param family AF_INET, AF_INET6, ...
+	 * @throw SocketError on error
+	 */
+	Internet(const std::string &host, unsigned port, int family);
+};
+
+#if !defined(_WIN32)
+
+/**
+ * @class Unix
+ * @brief unix family sockets
+ *
+ * Create an address to a specific path. Only available on Unix.
+ */
+class Unix : public SocketAddress {
+public:
+	/**
+	 * Construct an address to a path.
+	 *
+	 * @param path the path
+	 * @param rm remove the file before (default: false)
+	 */
+	Unix(const std::string &path, bool rm = false);
+};
+
+#endif // ! !_WIN32
+
+} // !address
+
+#endif // !_SOCKET_ADDRESS_NG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketListener.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,330 @@
+/*
+ * SocketListener.cpp -- portable select() wrapper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "SocketListener.h"
+
+/* --------------------------------------------------------
+ * Select implementation
+ * -------------------------------------------------------- */
+
+namespace {
+
+/**
+ * @class SelectMethod
+ * @brief Implements select(2)
+ *
+ * This class is the fallback of any other method, it is not preferred at all for many reasons.
+ */
+class SelectMethod final : public SocketListenerInterface {
+private:
+	std::map<Socket::Handle, std::pair<std::reference_wrapper<Socket>, int>> m_table;
+
+public:
+	void set(Socket &s, int direction) override
+	{
+		if (m_table.count(s.handle()) > 0) {
+			m_table.at(s.handle()).second |= direction;
+		} else {
+			m_table.insert({s.handle(), {s, direction}});
+		}
+
+	}
+
+	void unset(Socket &s, int direction) override
+	{
+		if (m_table.count(s.handle()) != 0) {
+			m_table.at(s.handle()).second &= ~(direction);
+
+			// If no read, no write is requested, remove it
+			if (m_table.at(s.handle()).second == 0) {
+				m_table.erase(s.handle());
+			}
+		}
+	}
+
+	void remove(Socket &sc) override
+	{
+		m_table.erase(sc.handle());
+	}
+
+	void clear() override
+	{
+		m_table.clear();
+	}
+
+	SocketStatus select(int ms) override
+	{
+		auto result = selectMultiple(ms);
+
+		if (result.size() == 0) {
+			throw SocketError(SocketError::System, "select", "No socket found");
+		}
+
+		return result[0];
+	}
+
+	std::vector<SocketStatus> selectMultiple(int ms) override
+	{
+		timeval maxwait, *towait;
+		fd_set readset;
+		fd_set writeset;
+
+		FD_ZERO(&readset);
+		FD_ZERO(&writeset);
+
+		Socket::Handle max = 0;
+
+		for (auto &s : m_table) {
+			if (s.second.second & SocketListener::Read) {
+				FD_SET(s.first, &readset);
+			}
+			if (s.second.second & SocketListener::Write) {
+				FD_SET(s.first, &writeset);
+			}
+
+			if (s.first > max) {
+				max = s.first;
+			}
+		}
+
+		maxwait.tv_sec = 0;
+		maxwait.tv_usec = ms * 1000;
+
+		// Set to nullptr for infinite timeout.
+		towait = (ms < 0) ? nullptr : &maxwait;
+
+		auto error = ::select(max + 1, &readset, &writeset, nullptr, towait);
+		if (error == Socket::Error) {
+			throw SocketError(SocketError::System, "select");
+		}
+		if (error == 0) {
+			throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
+		}
+
+		std::vector<SocketStatus> sockets;
+
+		for (auto &c : m_table) {
+			if (FD_ISSET(c.first, &readset)) {
+				sockets.push_back({ c.second.first, SocketListener::Read });
+			}
+			if (FD_ISSET(c.first, &writeset)) {
+				sockets.push_back({ c.second.first, SocketListener::Write });
+			}
+		}
+
+		return sockets;
+	}
+};
+
+} // !namespace
+
+/* --------------------------------------------------------
+ * Poll implementation
+ * -------------------------------------------------------- */
+
+#if defined(SOCKET_HAVE_POLL)
+
+#if defined(_WIN32)
+#  include <Winsock2.h>
+#  define poll WSAPoll
+#else
+#  include <poll.h>
+#endif
+
+namespace {
+
+class PollMethod final : public SocketListenerInterface {
+private:
+	std::vector<pollfd> m_fds;
+	std::map<Socket::Handle, std::reference_wrapper<Socket>> m_lookup;
+
+	inline short topoll(int direction)
+	{
+		short result(0);
+
+		if (direction & SocketListener::Read)
+			result |= POLLIN;
+		if (direction & SocketListener::Write)
+			result |= POLLOUT;
+
+		return result;
+	}
+
+	inline int todirection(short event)
+	{
+		int direction{};
+
+		/*
+		 * Poll implementations mark the socket differently regarding
+		 * the disconnection of a socket.
+		 *
+		 * At least, even if POLLHUP or POLLIN is set, recv() always
+		 * return 0 so we mark the socket as readable.
+		 */
+		if ((event & POLLIN) || (event & POLLHUP))
+			direction |= SocketListener::Read;
+		if (event & POLLOUT)
+			direction |= SocketListener::Write;
+
+		return direction;
+	}
+
+public:
+	void set(Socket &s, int direction) override
+	{
+		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const auto &pfd) { return pfd.fd == s.handle(); });
+
+		// If found, add the new direction, otherwise add a new socket
+		if (it != m_fds.end())
+			it->events |= topoll(direction);
+		else {
+			m_lookup.insert({s.handle(), s});
+			m_fds.push_back({ s.handle(), topoll(direction), 0 });
+		}
+	}
+
+	void unset(Socket &s, int direction) override
+	{
+		for (auto i = m_fds.begin(); i != m_fds.end();) {
+			if (i->fd == s.handle()) {
+				i->events &= ~(topoll(direction));
+
+				if (i->events == 0) {
+					m_lookup.erase(i->fd);
+					i = m_fds.erase(i);
+				} else {
+					++i;
+				}
+			} else
+				++i;
+		}
+	}
+
+	void remove(Socket &s) override
+	{
+		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const auto &pfd) { return pfd.fd == s.handle(); });
+
+		if (it != m_fds.end()) {
+			m_fds.erase(it);
+			m_lookup.erase(s.handle());
+		}
+	}
+
+	void clear() override
+	{
+		m_fds.clear();
+		m_lookup.clear();
+	}
+
+	SocketStatus select(int ms) override
+	{
+		auto result = poll(m_fds.data(), m_fds.size(), ms);
+		if (result == 0)
+			throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
+		if (result < 0)
+			throw SocketError(SocketError::System, "poll");
+
+		for (auto &fd : m_fds) {
+			if (fd.revents != 0) {
+				return { m_lookup.at(fd.fd), todirection(fd.revents) };
+			}
+		}
+
+		throw SocketError(SocketError::System, "select", "No socket found");
+	}
+
+	std::vector<SocketStatus> selectMultiple(int ms) override
+	{
+		auto result = poll(m_fds.data(), m_fds.size(), ms);
+		if (result == 0) {
+			throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
+		}
+		if (result < 0) {
+			throw SocketError(SocketError::System, "poll");
+		}
+
+		std::vector<SocketStatus> sockets;
+		for (auto &fd : m_fds) {
+			if (fd.revents != 0) {
+				sockets.push_back({ m_lookup.at(fd.fd), todirection(fd.revents) });
+			}
+		}
+
+		return sockets;
+	}
+};
+
+} // !namespace
+
+#endif // !_SOCKET_HAVE_POLL
+
+/* --------------------------------------------------------
+ * SocketListener
+ * -------------------------------------------------------- */
+
+const int SocketListener::Read{1 << 0};
+const int SocketListener::Write{1 << 1};
+
+SocketListener::SocketListener(std::initializer_list<std::pair<std::reference_wrapper<Socket>, int>> list)
+	: SocketListener()
+{
+	for (const auto &p : list)
+		set(p.first, p.second);
+}
+
+SocketListener::SocketListener(SocketMethod method)
+{
+#if defined(SOCKET_HAVE_POLL)
+	if (method == SocketMethod::Poll)
+		m_interface = std::make_unique<PollMethod>();
+	else
+#endif
+		m_interface = std::make_unique<SelectMethod>();
+
+	(void)method;
+}
+
+void SocketListener::set(Socket &sc, int flags)
+{
+	if (m_map.count(sc) > 0) {
+		m_map[sc] |= flags;
+		m_interface->set(sc, flags);
+	} else {
+		m_map.insert({sc, flags});
+		m_interface->set(sc, flags);
+	}
+}
+
+void SocketListener::unset(Socket &sc, int flags) noexcept
+{
+	if (m_map.count(sc) > 0) {
+		m_map[sc] &= ~(flags);
+		m_interface->unset(sc, flags);
+
+		// No more flags, remove it
+		if (m_map[sc] == 0) {
+			m_map.erase(sc);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketListener.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,347 @@
+/*
+ * SocketListener.h -- portable select() wrapper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SOCKET_LISTENER_NG_H_
+#define _SOCKET_LISTENER_NG_H_
+
+#include <chrono>
+#include <functional>
+#include <initializer_list>
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "Socket.h"
+
+#if defined(_WIN32)
+#  if _WIN32_WINNT >= 0x0600
+#    define SOCKET_HAVE_POLL
+#  endif
+#else
+#  define SOCKET_HAVE_POLL
+#endif
+
+/**
+ * @enum SocketMethod
+ * @brief The SocketMethod enum
+ *
+ * Select the method of polling. It is only a preferred method, for example if you
+ * request for poll but it is not available, select will be used.
+ */
+enum class SocketMethod {
+	Select,				//!< select(2) method, fallback
+	Poll				//!< poll(2), everywhere possible
+};
+
+/**
+ * @struct SocketStatus
+ * @brief The SocketStatus struct
+ *
+ * Result of a select call, returns the first ready socket found with its
+ * direction.
+ */
+class SocketStatus {
+public:
+	Socket	&socket;		//!< which socket is ready
+	int	 direction;		//!< the direction
+};
+
+/**
+ * @class SocketListenerInterface
+ * @brief Implement the polling method
+ */
+class SocketListenerInterface {
+public:
+	/**
+	 * Default destructor.
+	 */
+	virtual ~SocketListenerInterface() = default;
+
+	/**
+	 * Add a socket with a specified direction.
+	 *
+	 * @param s the socket
+	 * @param direction the direction
+	 */
+	virtual void set(Socket &sc, int direction) = 0;
+
+	/**
+	 * Remove a socket with a specified direction.
+	 *
+	 * @param s the socket
+	 * @param direction the direction
+	 */
+	virtual void unset(Socket &sc, int direction) = 0;
+
+	/**
+	 * Remove completely a socket.
+	 *
+	 * @param sc the socket to remove
+	 */
+	virtual void remove(Socket &sc) = 0;
+
+	/**
+	 * Remove all sockets.
+	 */
+	virtual void clear() = 0;
+
+	/**
+	 * Select one socket.
+	 *
+	 * @param ms the number of milliseconds to wait, -1 means forever
+	 * @return the socket status
+	 * @throw error::Failure on failure
+	 * @throw error::Timeout on timeout
+	 */
+	virtual SocketStatus select(int ms) = 0;
+
+	/**
+	 * Select many sockets.
+	 *
+	 * @param ms the number of milliseconds to wait, -1 means forever
+	 * @return a vector of ready sockets
+	 * @throw error::Failure on failure
+	 * @throw error::Timeout on timeout
+	 */
+	virtual std::vector<SocketStatus> selectMultiple(int ms) = 0;
+};
+
+/**
+ * @class SocketListener
+ * @brief Synchronous multiplexing
+ *
+ * Convenient wrapper around the select() system call.
+ *
+ * This class is implemented using a bridge pattern to allow different uses
+ * of listener implementation.
+ *
+ * Currently, poll and select() are available.
+ *
+ * This wrappers takes abstract sockets as non-const reference but it does not
+ * own them so you must take care that sockets are still alive until the
+ * SocketListener is destroyed.
+ */
+class SocketListener final {
+public:
+#if defined(SOCKET_HAVE_POLL)
+	static constexpr const SocketMethod PreferredMethod = SocketMethod::Poll;
+#else
+	static constexpr const SocketMethod PreferredMethod = SocketMethod::Select;
+#endif
+
+	static const int Read;
+	static const int Write;
+
+	using Map = std::map<std::reference_wrapper<Socket>, int>;
+	using Iface = std::unique_ptr<SocketListenerInterface>;
+
+private:
+	Map m_map;
+	Iface m_interface;
+
+public:
+	/**
+	 * Move constructor.
+	 *
+	 * @param other the other object
+	 */
+	SocketListener(SocketListener &&other) = default;
+
+	/**
+	 * Move operator.
+	 *
+	 * @param other the other object
+	 * @return this
+	 */
+	SocketListener &operator=(SocketListener &&other) = default;
+
+	/**
+	 * Create a socket listener.
+	 *
+	 * @param method the preferred method
+	 */
+	SocketListener(SocketMethod method = PreferredMethod);
+
+	/**
+	 * Create a listener from a list of sockets.
+	 *
+	 * @param list the list
+	 */
+	SocketListener(std::initializer_list<std::pair<std::reference_wrapper<Socket>, int>> list);
+
+	/**
+	 * Return an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() noexcept
+	{
+		return m_map.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() const noexcept
+	{
+		return m_map.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cbegin() const noexcept
+	{
+		return m_map.cbegin();
+	}
+
+	/**
+	 * Return an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() noexcept
+	{
+		return m_map.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() const noexcept
+	{
+		return m_map.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cend() const noexcept
+	{
+		return m_map.cend();
+	}
+
+	/**
+	 * Add a socket to the listener.
+	 *
+	 * @param sc the socket
+	 * @param direction (may be OR'ed)
+	 */
+	void set(Socket &sc, int direction);
+
+	/**
+	 * Unset a socket from the listener, only the direction is removed
+	 * unless the two directions are requested.
+	 *
+	 * For example, if you added a socket for both reading and writing,
+	 * unsetting the write direction will keep the socket for reading.
+	 *
+	 * @param sc the socket
+	 * @param direction the direction (may be OR'ed)
+	 * @see remove
+	 */
+	void unset(Socket &sc, int direction) noexcept;
+
+	/**
+	 * Remove completely the socket from the listener.
+	 *
+	 * @param sc the socket
+	 */
+	inline void remove(Socket &sc) noexcept
+	{
+		m_map.erase(sc);
+		m_interface->remove(sc);
+	}
+
+	/**
+	 * Remove all sockets.
+	 */
+	inline void clear() noexcept
+	{
+		m_map.clear();
+		m_interface->clear();
+	}
+
+	/**
+	 * Get the number of sockets in the listener.
+	 */
+	unsigned size() const noexcept
+	{
+		return m_map.size();
+	}
+
+	/**
+	 * Select a socket. Waits for a specific amount of time specified as the duration.
+	 *
+	 * @param duration the duration
+	 * @return the socket ready
+	 */
+	template <typename Rep, typename Ratio>
+	inline SocketStatus select(const std::chrono::duration<Rep, Ratio> &duration)
+	{
+		auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
+
+		return m_interface->select(cvt.count());
+	}
+
+	/**
+	 * Overload with milliseconds.
+	 *
+	 * @param timeout the optional timeout in milliseconds
+	 * @return the socket ready
+	 */
+	inline SocketStatus select(int timeout = -1)
+	{
+		return m_interface->select(timeout);
+	}
+
+	/**
+	 * Select multiple sockets.
+	 *
+	 * @param duration the duration
+	 * @return the socket ready
+	 */
+	template <typename Rep, typename Ratio>
+	inline std::vector<SocketStatus> selectMultiple(const std::chrono::duration<Rep, Ratio> &duration)
+	{
+		auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
+
+		return m_interface->selectMultiple(cvt.count());
+	}
+
+	/**
+	 * Overload with milliseconds.
+	 *
+	 * @return the socket ready
+	 */
+	inline std::vector<SocketStatus> selectMultiple(int timeout = -1)
+	{
+		return m_interface->selectMultiple(timeout);
+	}
+};
+
+#endif // !_SOCKET_LISTENER_NG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketSsl.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,228 @@
+/*
+ * SocketSsl.cpp -- OpenSSL extension for sockets
+ *
+ * Copyright (c) 2013, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "SocketAddress.h"
+#include "SocketListener.h"
+#include "SocketSsl.h"
+
+namespace {
+
+const SSL_METHOD *sslMethod(int mflags)
+{
+	if (mflags & SocketSslOptions::All)
+		return SSLv23_method();
+	if (mflags & SocketSslOptions::SSLv3)
+		return SSLv3_method();
+	if (mflags & SocketSslOptions::TLSv1)
+		return TLSv1_method();
+
+	return SSLv23_method();
+}
+
+inline std::string sslError(int error)
+{
+	return ERR_reason_error_string(error);
+}
+
+inline int toDirection(int error)
+{
+	if (error == SocketError::WouldBlockRead)
+		return SocketListener::Read;
+	if (error ==  SocketError::WouldBlockWrite)
+		return SocketListener::Write;
+
+	return 0;
+}
+
+} // !namespace
+
+std::mutex SocketSsl::s_sslMutex;
+std::atomic<bool> SocketSsl::s_sslInitialized{false};
+
+SocketSsl::SocketSsl(Socket::Handle handle, SSL_CTX *context, SSL *ssl)
+	: SocketAbstractTcp(handle)
+	, m_context(context, SSL_CTX_free)
+	, m_ssl(ssl, SSL_free)
+{
+#if !defined(SOCKET_NO_SSL_INIT)
+	if (!s_sslInitialized)
+		sslInitialize();
+#endif
+}
+
+SocketSsl::SocketSsl(int family, int protocol, SocketSslOptions options)
+	: SocketAbstractTcp(family, protocol)
+	, m_options(std::move(options))
+{
+#if !defined(SOCKET_NO_SSL_INIT)
+	if (!s_sslInitialized)
+		sslInitialize();
+#endif
+}
+
+void SocketSsl::connect(const SocketAddress &address)
+{
+	standardConnect(address);
+
+	// Context first
+	auto context = SSL_CTX_new(sslMethod(m_options.method));
+
+	m_context = ContextHandle(context, SSL_CTX_free);
+
+	// SSL object then
+	auto ssl = SSL_new(context);
+
+	m_ssl = SslHandle(ssl, SSL_free);
+
+	SSL_set_fd(ssl, m_handle);
+
+	auto ret = SSL_connect(ssl);
+
+	if (ret <= 0) {
+		auto error = SSL_get_error(ssl, ret);
+
+		if (error == SSL_ERROR_WANT_READ) {
+			throw SocketError(SocketError::WouldBlockRead, "connect", "Operation in progress");
+		} else if (error == SSL_ERROR_WANT_WRITE) {
+			throw SocketError(SocketError::WouldBlockWrite, "connect", "Operation in progress");
+		} else {
+			throw SocketError(SocketError::System, "connect", sslError(error));
+		}
+	}
+
+	m_state = SocketState::Connected;
+}
+
+void SocketSsl::waitConnect(const SocketAddress &address, int timeout)
+{
+	try {
+		// Initial try
+		connect(address);
+	} catch (const SocketError &ex) {
+		if (ex.code() == SocketError::WouldBlockRead || ex.code() == SocketError::WouldBlockWrite) {
+			SocketListener listener{{*this, toDirection(ex.code())}};
+
+			listener.select(timeout);
+
+			// Second try
+			connect(address);
+		} else {
+			throw;
+		}
+	}
+}
+
+SocketSsl SocketSsl::accept()
+{
+	SocketAddress dummy;
+
+	return accept(dummy);
+}
+
+SocketSsl SocketSsl::accept(SocketAddress &info)
+{
+	auto client = standardAccept(info);
+	auto context = SSL_CTX_new(sslMethod(m_options.method));
+
+	if (m_options.certificate.size() > 0)
+		SSL_CTX_use_certificate_file(context, m_options.certificate.c_str(), SSL_FILETYPE_PEM);
+	if (m_options.privateKey.size() > 0)
+		SSL_CTX_use_PrivateKey_file(context, m_options.privateKey.c_str(), SSL_FILETYPE_PEM);
+	if (m_options.verify && !SSL_CTX_check_private_key(context)) {
+		client.close();
+		throw SocketError(SocketError::System, "accept", "certificate failure");
+	}
+
+	// SSL object
+	auto ssl = SSL_new(context);
+
+	SSL_set_fd(ssl, client.handle());
+
+	auto ret = SSL_accept(ssl);
+
+	if (ret <= 0) {
+		auto error = SSL_get_error(ssl, ret);
+
+		if (error == SSL_ERROR_WANT_READ) {
+			throw SocketError(SocketError::WouldBlockRead, "accept", "Operation would block");
+		} else if (error == SSL_ERROR_WANT_WRITE) {
+			throw SocketError(SocketError::WouldBlockWrite, "accept", "Operation would block");
+		} else {
+			throw SocketError(SocketError::System, "accept", sslError(error));
+		}
+	}
+
+	return SocketSsl(client.handle(), context, ssl);
+}
+
+unsigned SocketSsl::recv(void *data, unsigned len)
+{
+	auto nbread = SSL_read(m_ssl.get(), data, len);
+
+	if (nbread <= 0) {
+		auto error = SSL_get_error(m_ssl.get(), nbread);
+
+		if (error == SSL_ERROR_WANT_READ) {
+			throw SocketError(SocketError::WouldBlockRead, "recv", "Operation would block");
+		} else if (error == SSL_ERROR_WANT_WRITE) {
+			throw SocketError(SocketError::WouldBlockWrite, "recv", "Operation would block");
+		} else {
+			throw SocketError(SocketError::System, "recv", sslError(error));
+		}
+	}
+
+	return nbread;
+}
+
+unsigned SocketSsl::waitRecv(void *data, unsigned len, int timeout)
+{
+	SocketListener listener{{*this, SocketListener::Read}};
+
+	listener.select(timeout);
+
+	return recv(data, len);
+}
+
+unsigned SocketSsl::send(const void *data, unsigned len)
+{
+	auto nbread = SSL_write(m_ssl.get(), data, len);
+
+	if (nbread <= 0) {
+		auto error = SSL_get_error(m_ssl.get(), nbread);
+
+		if (error == SSL_ERROR_WANT_READ) {
+			throw SocketError(SocketError::WouldBlockRead, "send", "Operation would block");
+		} else if (error == SSL_ERROR_WANT_WRITE) {
+			throw SocketError(SocketError::WouldBlockWrite, "send", "Operation would block");
+		} else {
+			throw SocketError(SocketError::System, "send", sslError(error));
+		}
+	}
+
+	return nbread;
+}
+
+unsigned SocketSsl::waitSend(const void *data, unsigned len, int timeout)
+{
+	SocketListener listener{{*this, SocketListener::Write}};
+
+	listener.select(timeout);
+
+	return send(data, len);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketSsl.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,215 @@
+/*
+ * SocketSsl.h -- OpenSSL extension for sockets
+ *
+ * Copyright (c) 2013, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SOCKET_SSL_NG_H_
+#define _SOCKET_SSL_NG_H_
+
+#include <atomic>
+#include <mutex>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+
+#include "SocketTcp.h"
+
+/**
+ * @class SocketSslOptions
+ * @brief Options for SocketSsl
+ */
+class SocketSslOptions {
+public:
+	/**
+	 * @brief Method
+	 */
+	enum {
+		SSLv3	= (1 << 0),
+		TLSv1	= (1 << 1),
+		All	= (0xf)
+	};
+
+	int		method{All};		//!< The method
+	std::string	certificate;		//!< The certificate path
+	std::string	privateKey;		//!< The private key file
+	bool		verify{false};		//!< Verify or not
+
+	/**
+	 * Default constructor.
+	 */
+	SocketSslOptions() = default;
+
+	/**
+	 * More advanced constructor.
+	 *
+	 * @param method the method requested
+	 * @param certificate the certificate file
+	 * @param key the key file
+	 * @param verify set to true to verify
+	 */
+	SocketSslOptions(int method, std::string certificate, std::string key, bool verify = false)
+		: method(method)
+		, certificate(std::move(certificate))
+		, privateKey(std::move(key))
+		, verify(verify)
+	{
+	}
+};
+
+/**
+ * @class SocketSsl
+ * @brief SSL interface for sockets
+ *
+ * This class derives from SocketAbstractTcp and provide SSL support through OpenSSL.
+ */
+class SocketSsl : public SocketAbstractTcp {
+public:
+	using ContextHandle = std::unique_ptr<SSL_CTX, void (*)(SSL_CTX *)>;
+	using SslHandle = std::unique_ptr<SSL, void (*)(SSL *)>;
+
+private:
+	static std::mutex s_sslMutex;
+	static std::atomic<bool> s_sslInitialized;
+
+	ContextHandle m_context{nullptr, nullptr};
+	SslHandle m_ssl{nullptr, nullptr};
+	SocketSslOptions m_options;
+
+public:
+	using SocketAbstractTcp::recv;
+	using SocketAbstractTcp::waitRecv;
+	using SocketAbstractTcp::send;
+	using SocketAbstractTcp::waitSend;
+
+	/**
+	 * Close OpenSSL library.
+	 */
+	static inline void sslTerminate()
+	{
+		ERR_free_strings();
+	}
+
+	/**
+	 * Open SSL library.
+	 */
+	static inline void sslInitialize()
+	{
+		std::lock_guard<std::mutex> lock(s_sslMutex);
+
+		if (!s_sslInitialized) {
+			s_sslInitialized = true;
+
+			SSL_library_init();
+			SSL_load_error_strings();
+
+			std::atexit(sslTerminate);
+		}
+	}
+
+	/**
+	 * Create a SocketSsl from an already created one.
+	 *
+	 * @param handle the native handle
+	 * @param context the context
+	 * @param ssl the ssl object
+	 */
+	SocketSsl(Socket::Handle handle, SSL_CTX *context, SSL *ssl);
+
+	/**
+	 * Open a SSL socket with the specified family. Automatically
+	 * use SOCK_STREAM as the type.
+	 *
+	 * @param family the family
+	 * @param options the options
+	 */
+	SocketSsl(int family, int protocol, SocketSslOptions options = {});
+
+	/**
+	 * Accept a SSL TCP socket.
+	 *
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketSsl accept();
+
+	/**
+	 * Accept a SSL TCP socket.
+	 *
+	 * @param info the client information
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketSsl accept(SocketAddress &info);
+
+	/**
+	 * Accept a SSL TCP socket.
+	 *
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketSsl waitAccept(int timeout);
+
+	/**
+	 * Accept a SSL TCP socket.
+	 *
+	 * @param info the client information
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketSsl waitAccept(SocketAddress &info, int timeout);
+
+	/**
+	 * Connect to an end point.
+	 *
+	 * @param address the address
+	 * @throw SocketError on error
+	 */
+	void connect(const SocketAddress &address);
+
+	/**
+	 * Connect to an end point.
+	 *
+	 * @param timeout the maximum timeout in milliseconds
+	 * @param address the address
+	 * @throw SocketError on error
+	 */
+	void waitConnect(const SocketAddress &address, int timeout);
+
+	/**
+	 * @copydoc SocketAbstractTcp::recv
+	 */
+	unsigned recv(void *data, unsigned length) override;
+
+	/**
+	 * @copydoc SocketAbstractTcp::recv
+	 */
+	unsigned waitRecv(void *data, unsigned length, int timeout) override;
+
+	/**
+	 * @copydoc SocketAbstractTcp::recv
+	 */
+	unsigned send(const void *data, unsigned length) override;
+
+	/**
+	 * @copydoc SocketAbstractTcp::recv
+	 */
+	unsigned waitSend(const void *data, unsigned length, int timeout) override;
+};
+
+#endif // !_SOCKET_SSL_NG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketTcp.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,227 @@
+/*
+ * SocketTcp.cpp -- portable C++ socket wrappers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "SocketAddress.h"
+#include "SocketListener.h"
+#include "SocketTcp.h"
+
+/* --------------------------------------------------------
+ * SocketAbstractTcp
+ * -------------------------------------------------------- */
+
+void SocketAbstractTcp::listen(int max)
+{
+	if (::listen(m_handle, max) == Error)
+		throw SocketError(SocketError::System, "listen");
+}
+
+Socket SocketAbstractTcp::standardAccept(SocketAddress &info)
+{
+	Socket::Handle handle;
+
+	// Store the information
+	sockaddr_storage address;
+	socklen_t addrlen;
+
+	addrlen = sizeof (sockaddr_storage);
+	handle = ::accept(m_handle, reinterpret_cast<sockaddr *>(&address), &addrlen);
+
+	if (handle == Invalid) {
+#if defined(_WIN32)
+		int error = WSAGetLastError();
+
+		if (error == WSAEWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockRead, "accept", error);
+
+		throw SocketError(SocketError::System, "accept", error);
+#else
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockRead, "accept");
+
+		throw SocketError(SocketError::System, "accept");
+#endif
+	}
+
+	info = SocketAddress(address, addrlen);
+
+	return Socket(handle);
+}
+
+void SocketAbstractTcp::standardConnect(const SocketAddress &address)
+{
+	if (m_state == SocketState::Connected)
+		return;
+
+	auto &sa = address.address();
+	auto addrlen = address.length();
+
+	if (::connect(m_handle, reinterpret_cast<const sockaddr *>(&sa), addrlen) == Error) {
+		/*
+		 * Determine if the error comes from a non-blocking connect that cannot be
+		 * accomplished yet.
+		 */
+#if defined(_WIN32)
+		int error = WSAGetLastError();
+
+		if (error == WSAEWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockWrite, "connect", error);
+
+		throw SocketError(SocketError::System, "connect", error);
+#else
+		if (errno == EINPROGRESS)
+			throw SocketError(SocketError::WouldBlockWrite, "connect");
+
+		throw SocketError(SocketError::System, "connect");
+#endif
+	}
+
+	m_state = SocketState::Connected;
+}
+
+/* --------------------------------------------------------
+ * SocketTcp
+ * -------------------------------------------------------- */
+
+SocketTcp SocketTcp::accept()
+{
+	SocketAddress dummy;
+
+	return accept(dummy);
+}
+
+SocketTcp SocketTcp::accept(SocketAddress &info)
+{
+	return standardAccept(info);
+}
+
+void SocketTcp::connect(const SocketAddress &address)
+{
+	return standardConnect(address);
+}
+
+void SocketTcp::waitConnect(const SocketAddress &address, int timeout)
+{
+	if (m_state == SocketState::Connected)
+		return;
+
+	// Initial try
+	try {
+		connect(address);
+	} catch (const SocketError &ex) {
+		if (ex.code() == SocketError::WouldBlockWrite) {
+			SocketListener listener{{*this, SocketListener::Write}};
+
+			listener.select(timeout);
+
+			// Socket is writable? Check if there is an error
+
+			int error = get<int>(SOL_SOCKET, SO_ERROR);
+
+			if (error) {
+				throw SocketError(SocketError::System, "connect", error);
+			}
+		} else {
+			throw;
+		}
+	}
+
+	m_state = SocketState::Connected;
+}
+
+SocketTcp SocketTcp::waitAccept(int timeout)
+{
+	SocketAddress dummy;
+
+	return waitAccept(dummy, timeout);
+}
+
+SocketTcp SocketTcp::waitAccept(SocketAddress &info, int timeout)
+{
+	SocketListener listener{{*this, SocketListener::Read}};
+
+	listener.select(timeout);
+
+	return accept(info);
+}
+
+unsigned SocketTcp::recv(void *data, unsigned dataLen)
+{
+	int nbread;
+
+	nbread = ::recv(m_handle, (Socket::Arg)data, dataLen, 0);
+	if (nbread == Error) {
+#if defined(_WIN32)
+		int error = WSAGetLastError();
+
+		if (error == WSAEWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockRead, "recv", error)
+
+		throw SocketError(SocketError::System, "recv", error);
+#else
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockRead, "recv");
+
+		throw SocketError(SocketError::System, "recv");
+#endif
+	} else if (nbread == 0)
+		m_state = SocketState::Closed;
+
+	return (unsigned)nbread;
+}
+
+unsigned SocketTcp::waitRecv(void *data, unsigned length, int timeout)
+{
+	SocketListener listener{{*this, SocketListener::Read}};
+
+	listener.select(timeout);
+
+	return recv(data, length);
+}
+
+unsigned SocketTcp::send(const void *data, unsigned length)
+{
+	int nbsent;
+
+	nbsent = ::send(m_handle, (Socket::ConstArg)data, length, 0);
+	if (nbsent == Error) {
+#if defined(_WIN32)
+		int error = WSAGetLastError();
+
+		if (error == WSAEWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockWrite, "send", error);
+
+		throw SocketError(SocketError::System, "send", error);
+#else
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockWrite, "send");
+
+		throw SocketError(SocketError::System, "send");
+#endif
+	}
+
+	return (unsigned)nbsent;
+}
+
+unsigned SocketTcp::waitSend(const void *data, unsigned length, int timeout)
+{
+	SocketListener listener{{*this, SocketListener::Write}};
+
+	listener.select(timeout);
+
+	return send(data, length);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketTcp.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,261 @@
+/*
+ * SocketTcp.h -- portable C++ socket wrappers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SOCKET_TCP_NG_H_
+#define _SOCKET_TCP_NG_H_
+
+#include "Socket.h"
+
+/**
+ * @class SocketAbstractTcp
+ * @brief Base class for TCP sockets
+ *
+ * This abstract class provides standard TCP functions for both clear
+ * and SSL implementation.
+ *
+ * It does not contain default accept() and connect() because they varies too
+ * much between standard and SSL. Also, the accept() function return different
+ * types.
+ */
+class SocketAbstractTcp : public Socket {
+protected:
+	Socket standardAccept(SocketAddress &address);
+	void standardConnect(const SocketAddress &address);
+
+public:
+	/**
+	 * Construct an abstract socket from an already made socket.
+	 *
+	 * @param s the socket
+	 */
+	inline SocketAbstractTcp(Socket s)
+		: Socket(s)
+	{
+	}
+
+	/**
+	 * Construct a standard TCP socket. The type is automatically
+	 * set to SOCK_STREAM.
+	 *
+	 * @param domain the domain
+	 * @param protocol the protocol
+	 * @throw SocketError on error
+	 */
+	inline SocketAbstractTcp(int domain, int protocol)
+		: Socket(domain, SOCK_STREAM, protocol)
+	{
+	}
+
+	/**
+	 * Listen for pending connection.
+	 *
+	 * @param max the maximum number
+	 */
+	void listen(int max = 128);
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param count the number of bytes to receive
+	 * @return the string
+	 * @throw SocketError on error
+	 */
+	inline std::string recv(unsigned count)
+	{
+		std::string result;
+
+		result.resize(count);
+		auto n = recv(const_cast<char *>(result.data()), count);
+		result.resize(n);
+
+		return result;
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param count the number of bytes to receive
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the string
+	 * @throw SocketError on error
+	 */
+	inline std::string waitRecv(unsigned count, int timeout)
+	{
+		std::string result;
+
+		result.resize(count);
+		auto n = waitRecv(const_cast<char *>(result.data()), count, timeout);
+		result.resize(n);
+
+		return result;
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param data the string to send
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	inline unsigned send(const std::string &data)
+	{
+		return send(data.c_str(), data.size());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param data the string to send
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	inline unsigned waitSend(const std::string &data, int timeout)
+	{
+		return waitSend(data.c_str(), data.size(), timeout);
+	}
+
+	/**
+	 * Receive data.
+	 *
+	 * @param data the destination buffer
+	 * @param length the buffer length
+	 * @return the number of bytes received
+	 * @throw SocketError on error
+	 */
+	virtual unsigned recv(void *data, unsigned length) = 0;
+
+	/**
+	 * Receive data.
+	 *
+	 * @param data the destination buffer
+	 * @param length the buffer length
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the number of bytes received
+	 * @throw SocketError on error
+	 */
+	virtual unsigned waitRecv(void *data, unsigned length, int timeout) = 0;
+
+	/**
+	 * Send data.
+	 *
+	 * @param data the buffer
+	 * @param length the buffer length
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	virtual unsigned send(const void *data, unsigned length) = 0;
+
+	/**
+	 * Send data.
+	 *
+	 * @param data the buffer
+	 * @param length the buffer length
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	virtual unsigned waitSend(const void *data, unsigned length, int timeout) = 0;
+};
+
+/**
+ * @class SocketTcp
+ * @brief End-user class for TCP sockets
+ */
+class SocketTcp : public SocketAbstractTcp {
+public:
+	using SocketAbstractTcp::SocketAbstractTcp;
+	using SocketAbstractTcp::recv;
+	using SocketAbstractTcp::waitRecv;
+	using SocketAbstractTcp::send;
+	using SocketAbstractTcp::waitSend;
+
+	/**
+	 * Accept a clear TCP socket.
+	 *
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketTcp accept();
+
+	/**
+	 * Accept a clear TCP socket.
+	 *
+	 * @param info the client information
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketTcp accept(SocketAddress &info);
+
+	/**
+	 * Accept a clear TCP socket.
+	 *
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketTcp waitAccept(int timeout);
+
+	/**
+	 * Accept a clear TCP socket.
+	 *
+	 * @param info the client information
+	 * @param timeout the maximum timeout in milliseconds
+	 * @return the socket
+	 * @throw SocketError on error
+	 */
+	SocketTcp waitAccept(SocketAddress &info, int timeout);
+
+	/**
+	 * Connect to an end point.
+	 *
+	 * @param address the address
+	 * @throw SocketError on error
+	 */
+	void connect(const SocketAddress &address);
+
+	/**
+	 * Connect to an end point.
+	 *
+	 * @param timeout the maximum timeout in milliseconds
+	 * @param address the address
+	 * @throw SocketError on error
+	 */
+	void waitConnect(const SocketAddress &address, int timeout);
+
+	/**
+	 * @copydoc SocketAbstractTcp::recv
+	 */
+	unsigned recv(void *data, unsigned length) override;
+
+	/**
+	 * @copydoc SocketAbstractTcp::waitRecv
+	 */
+	unsigned waitRecv(void *data, unsigned length, int timeout) override;
+
+	/**
+	 * @copydoc SocketAbstractTcp::send
+	 */
+	unsigned send(const void *data, unsigned length) override;
+
+	/**
+	 * @copydoc SocketAbstractTcp::waitSend
+	 */
+	unsigned waitSend(const void *data, unsigned length, int timeout) override;
+};
+
+#endif // !_SOCKET_TCP_NG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketUdp.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,81 @@
+/*
+ * SocketUdp.cpp -- portable C++ socket wrappers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "SocketAddress.h"
+#include "SocketUdp.h"
+
+SocketUdp::SocketUdp(int domain, int protocol)
+	: Socket(domain, SOCK_DGRAM, protocol)
+{
+}
+
+unsigned SocketUdp::recvfrom(void *data, unsigned length, SocketAddress &info)
+{
+	int nbread;
+
+	// Store information
+	sockaddr_storage address;
+	socklen_t addrlen;
+
+	addrlen = sizeof (struct sockaddr_storage);
+	nbread = ::recvfrom(m_handle, (Socket::Arg)data, length, 0, (sockaddr *)&address, &addrlen);
+
+	info = SocketAddress(address, addrlen);
+
+	if (nbread == Error) {
+#if defined(_WIN32)
+		int error = WSAGetLastError();
+
+		if (error == WSAEWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockRead, "recvfrom", error);
+
+		throw SocketError(SocketError::System, "recvfrom", error);
+#else
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockRead, "recvfrom");
+
+		throw SocketError(SocketError::System, "recvfrom");
+#endif
+	}
+
+	return (unsigned)nbread;
+}
+
+unsigned SocketUdp::sendto(const void *data, unsigned length, const SocketAddress &info)
+{
+	int nbsent;
+
+	nbsent = ::sendto(m_handle, (Socket::ConstArg)data, length, 0, (const sockaddr *)&info.address(), info.length());
+	if (nbsent == Error) {
+#if defined(_WIN32)
+		int error = WSAGetLastError();
+
+		if (error == WSAEWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockWrite, "sendto", error);
+
+		throw SocketError(SocketError::System, "sendto", error);
+#else
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			throw SocketError(SocketError::WouldBlockWrite, "sendto");
+
+		throw SocketError(SocketError::System, "sendto");
+#endif
+	}
+
+	return (unsigned)nbsent;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Socket/SocketUdp.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,93 @@
+/*
+ * SocketUdp.h -- portable C++ socket wrappers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SOCKET_UDP_NG_H_
+#define _SOCKET_UDP_NG_H_
+
+#include "Socket.h"
+
+/**
+ * @class SocketUdp
+ * @brief UDP implementation for sockets
+ */
+class SocketUdp : public Socket {
+public:
+	/**
+	 * Construct a UDP socket. The type is automatically set to SOCK_DGRAM.
+	 *
+	 * @param domain the domain (e.g AF_INET)
+	 * @param protocol the protocol (usually 0)
+	 */
+	SocketUdp(int domain, int protocol);
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param data the data
+	 * @param address the address
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	inline unsigned sendto(const std::string &data, const SocketAddress &address)
+	{
+		return sendto(data.c_str(), data.length(), address);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @param data the data
+	 * @param info the client information
+	 * @return the string
+	 * @throw SocketError on error
+	 */
+	inline std::string recvfrom(unsigned count, SocketAddress &info)
+	{
+		std::string result;
+
+		result.resize(count);
+		auto n = recvfrom(const_cast<char *>(result.data()), count, info);
+		result.resize(n);
+
+		return result;
+	}
+
+	/**
+	 * Receive data from an end point.
+	 *
+	 * @param data the destination buffer
+	 * @param length the buffer length
+	 * @param info the client information
+	 * @return the number of bytes received
+	 * @throw SocketError on error
+	 */
+	virtual unsigned recvfrom(void *data, unsigned length, SocketAddress &info);
+
+	/**
+	 * Send data to an end point.
+	 *
+	 * @param data the buffer
+	 * @param length the buffer length
+	 * @param address the client address
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	virtual unsigned sendto(const void *data, unsigned length, const SocketAddress &address);
+};
+
+#endif // !_SOCKET_UDP_NG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Treenode/TreeNode.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,524 @@
+/*
+ * TreeNode.h -- C++11 pointer-free N-ary tree
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TREE_NODE_H_
+#define _TREE_NODE_H_
+
+/**
+ * @file TreeNode.h
+ * @brief N-ary tree without pointers
+ */
+
+#include <algorithm>
+#include <deque>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+
+namespace {
+
+/**
+ * @class TypeTraits
+ * @brief Some checks on the type
+ *
+ * Provides the following members depending on the type:
+ *
+ *	equalityComparable	- If == comparison can be performed
+ */
+template <typename T>
+class TypeTraits {
+private:
+	/**
+	 * @class HasEqualsTo
+	 * @brief Check if the type is comparable
+	 *
+	 * Sets to true if the type T can is equality comparable.
+	 */
+	template <typename U>
+	class HasEqualsTo {
+	public:
+		using Yes	= char [2];
+		using No	= char [1];
+
+		static_assert(sizeof (char) != sizeof (long), "buy a new compiler");
+
+		template <typename Value>
+		static constexpr Yes &check(Value *u, decltype(*u == *u) * = nullptr);
+
+		static constexpr No &check(...);
+
+		static constexpr const bool value = sizeof (check((U *)0)) == sizeof (Yes);
+	};
+
+public:
+	static constexpr const bool equalityComparable = HasEqualsTo<T>::value;
+};
+
+} // !namespace
+
+/**
+ * @class TreeNode
+ * @brief Safe C++11 N-ary tree
+ *
+ * This class use a std::deque as the container, it allocate object on the heap to avoid useless
+ * copy and move when adding new elements.
+ */
+template <typename T>
+class TreeNode {
+private:
+	class Object {
+	public:
+		virtual T &get() = 0;
+		virtual std::unique_ptr<Object> clone() const = 0;
+	};
+
+	template <typename Value>
+	struct Proxy final : public Object {
+	private:
+		Value m_value;
+
+		Proxy(const Proxy &) = delete;
+		Proxy &operator=(const Proxy &) = delete;
+		Proxy(Proxy &&) = delete;
+		Proxy &operator=(Proxy &&) = delete;
+
+	public:
+		inline Proxy(Value &&value)
+			: m_value(std::move(value))
+		{
+		}
+
+		inline Proxy(const Value &value)
+			: m_value(value)
+		{
+		}
+
+		template <typename... Args>
+		inline Proxy(Args&&... args)
+			: m_value(std::forward<Args>(args)...)
+		{
+		}
+
+		T &get() override
+		{
+			return m_value;
+		}
+
+		std::unique_ptr<Object> clone() const override
+		{
+			return std::make_unique<Proxy<Value>>(m_value);
+		}
+	};
+
+	using Container	= std::deque<std::unique_ptr<Object>>;
+
+	TreeNode	*m_parent{nullptr};
+	Container	 m_children;
+
+public:
+	/**
+	 * Default constructor.
+	 */
+	TreeNode() = default;
+
+	/**
+	 * Default destructor.
+	 */
+	virtual ~TreeNode() = default;
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param other the other node
+	 */
+	TreeNode(const TreeNode &other)
+		: m_parent(nullptr)
+	{
+		for (const auto &c : other.m_children) {
+			m_children.push_back(c->clone());
+			m_children.back()->get().m_parent = this;
+		}
+	}
+
+	/**
+	 * Move constructor.
+	 *
+	 * @param other the other node
+	 */
+	TreeNode(TreeNode &&other)
+		: m_parent(nullptr)
+		, m_children(std::move(other.m_children))
+	{
+		// Update children to update to *this
+		for (auto &c : m_children)
+			c->get().m_parent = this;
+
+		other.m_children.clear();
+	}
+
+	/**
+	 * Copy assignment operator.
+	 *
+	 * @param other the other node
+	 */
+	TreeNode &operator=(const TreeNode &other)
+	{
+		m_children.clear();
+
+		for (const auto &c : other.m_children) {
+			m_children.push_back(c->clone());
+			m_children.back()->get().m_parent = this;
+		}
+
+		return *this;
+	}
+
+	/**
+	 * Move assignment operator.
+	 *
+	 * @param other the other node
+	 */
+	TreeNode &operator=(TreeNode &&other)
+	{
+		m_children = std::move(other.m_children);
+
+		// Update children to update to *this
+		for (auto &c : m_children)
+			c->get().m_parent = this;
+
+		other.m_children.clear();
+
+		return *this;
+	}
+
+	/**
+	 * Add a child node to the beginning.
+	 *
+	 * @param child the children
+	 */
+	template <typename Value>
+	inline void push(const Value &child)
+	{
+		m_children.push_front(std::make_unique<Proxy<Value>>(child));
+		m_children.front()->get().m_parent = this;
+	}
+
+	/**
+	 * Move to the beginning.
+	 *
+	 * @param child the children
+	 */
+	template <typename Value>
+	inline void push(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value>::type * = nullptr)
+	{
+		using Type = typename std::decay<Value>::type;
+
+		m_children.push_front(std::make_unique<Proxy<Type>>(std::move(child)));
+		m_children.front()->get().m_parent = this;
+	}
+
+	/**
+	 * Construct an element at the beginning in place.
+	 *
+	 * @param args the arguments
+	 */
+	template <typename... Args>
+	void pushNew(Args&&... args)
+	{
+		m_children.emplace_front(std::make_unique<Proxy<T>>(std::forward<Args>(args)...));
+		m_children.front()->get().m_parent = this;
+	}
+
+	/**
+	 * Add a child node to the end
+	 *
+	 * @param child the children
+	 */
+	template <typename Value>
+	inline void append(const Value &child)
+	{
+		m_children.push_back(std::make_unique<Proxy<Value>>(child));
+		m_children.back()->get().m_parent = this;
+	}
+
+	/**
+	 * Move a child node to the end
+	 *
+	 * @param child the children
+	 */
+	template <typename Value>
+	inline void append(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value>::type * = nullptr)
+	{
+		using Type = typename std::decay<Value>::type;
+
+		m_children.push_back(std::make_unique<Proxy<Type>>(std::move(child)));
+		m_children.back()->get().m_parent = this;
+	}
+
+	/**
+	 * Construct an element at the end in place.
+	 *
+	 * @param args the arguments
+	 */
+	template <typename... Args>
+	void appendNew(Args&&... args)
+	{
+		m_children.emplace_back(std::make_unique<Proxy<T>>(std::forward<Args>(args)...));
+		m_children.back()->get().m_parent = this;
+	}
+
+	/**
+	 * Count the number of children in this node.
+	 *
+	 * @return the number of children
+	 */
+	unsigned countChildren() const noexcept
+	{
+		return static_cast<unsigned>(m_children.size());
+	}
+
+	/**
+	 * Get the parent node.
+	 *
+	 * @return the parent node
+	 * @throw std::out_of_range if there is no parent
+	 */
+	T &parent()
+	{
+		if (!m_parent)
+			throw std::out_of_range("no parent");
+
+		return static_cast<T &>(*m_parent);
+	}
+
+	/**
+	 * Get the parent node.
+	 *
+	 * @return the parent node
+	 * @throw std::out_of_range if there is no parent
+	 */
+	const T &parent() const
+	{
+		if (!m_parent)
+			throw std::out_of_range("no parent");
+
+		return static_cast<const T &>(*m_parent);
+	}
+
+	/**
+	 * Check if the node is root (no parent).
+	 *
+	 * @return true if root
+	 */
+	bool isRoot() const noexcept
+	{
+		return m_parent == nullptr;
+	}
+
+	/**
+	 * Check if the node is leaf (no children).
+	 *
+	 * @return true if leaf
+	 */
+	bool isLeaf() const noexcept
+	{
+		return m_children.size() == 0;
+	}
+
+	/**
+	 * Remove a child from the node at the given index.
+	 *
+	 * @param index the position index
+	 * @throw std::out_of_range if index is out of bounds
+	 */
+	void remove(int index)
+	{
+		if (index < 0 || index >= static_cast<int>(m_children.size()))
+			throw std::out_of_range("index is out of range");
+
+		m_children.erase(m_children.begin() + index);
+	}
+
+	/**
+	 * Remove a child from the node, the child must exists and no comparison test is performed, only
+	 * object addresses are compared.
+	 *
+	 * @param value the value that exists in the node
+	 * @warn the removed object must not be used after the call
+	 */
+	void remove(T &value)
+	{
+		m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&] (auto &p) {
+			return &p->get() == &value;
+		}), m_children.end());
+	}
+
+	/**
+	 * Remove a child from the node, the value is tested using operator== and therefore may not exist in the container.
+	 *
+	 * @param value the value that can be compared
+	 * @warn the removed object must not be used after the call
+	 */
+	template <typename Value>
+	void removeSame(const Value &value, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr)
+	{
+		m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&] (auto &p) {
+			return p->get() == value;
+		}), m_children.end());
+	}
+
+	/**
+	 * Remove all children.
+	 */
+	void clear()
+	{
+		m_children.clear();
+	}
+
+	/**
+	 * Find a child in this node, the child address is used as the comparison so no equality operator is even called.
+	 *
+	 * @param child the child
+	 * @return the index or -1 if not found
+	 * @see indexOfSame
+	 */
+	int indexOf(const T &child) const noexcept
+	{
+		for (unsigned i = 0; i < m_children.size(); ++i)
+			if (&m_children[i]->get() == &child)
+				return i;
+
+		return -1;
+	}
+
+	/**
+	 * Find the index of a node that is equality comparable to value but may be not in the node.
+	 *
+	 * @param value the value to compare
+	 * @return the index or -1 if not found
+	 * @see indexOf
+	 */
+	template <typename Value>
+	int indexOfSame(const Value &value, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr) const noexcept
+	{
+		for (unsigned i = 0; i < m_children.size(); ++i)
+			if (m_children[i]->get() == value)
+				return i;
+
+		return -1;
+	}
+
+	/**
+	 * Iterate over all the nodes. The first node is also passed through
+	 * the callback.
+	 *
+	 * @param callback the callback
+	 */
+	template <typename Callback>
+	void map(Callback callback)
+	{
+		callback(static_cast<T &>(*this));
+
+		for (auto &v : m_children)
+			v->get().map(callback);
+	}
+
+	/**
+	 * Convert the tree to a flat list by appending to the output iterator.
+	 *
+	 * @param dest the destination iterator
+	 */
+	template <typename OutputIt>
+	void flat(OutputIt dest)
+	{
+		map([&] (const auto &value) {
+			*dest++ = value;
+		});
+	}
+
+	/**
+	 * Iterate all values and call the function when found.
+	 *
+	 * @param predicate the predicate
+	 * @param callable the callable to call when found
+	 * @return true if found
+	 */
+	template <typename UnaryPredicate, typename Callable>
+	bool search(UnaryPredicate predicate, Callable callable)
+	{
+		if (predicate(static_cast<const T &>(*this))) {
+			callable(static_cast<T &>(*this));
+			return true;
+		}
+
+		for (auto &v : m_children) {
+			if (v->get().search(predicate, callable))
+				return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Search and return the first value matching the predicate.
+	 *
+	 * @param predicate the predicate
+	 * @return the reference to the node
+	 * @throw std::out_of_range if not found
+	 */
+	template <typename UnaryPredicate>
+	T &search(UnaryPredicate predicate)
+	{
+		T *value{nullptr};
+
+		search(predicate, [&] (auto &ptr) {
+			value = &ptr;
+		});
+
+		if (value == nullptr)
+			throw std::out_of_range("node not found");
+
+		return *value;
+	}
+
+	/**
+	 * Access a child.
+	 *
+	 * @param index the index
+	 * @return the reference to the children node
+	 * @throw std::out_of_range on out of bounds
+	 */
+	T &operator[](int index)
+	{
+		return static_cast<T &>(m_children.at(index)->get());
+	}
+
+	/**
+	 * Access a child.
+	 *
+	 * @param index the index
+	 * @return the reference to the children node
+	 * @throw std::out_of_range on out of bounds
+	 */
+	const T &operator[](int index) const
+	{
+		return static_cast<const T &>(m_children.at(index)->get());
+	}
+};
+
+#endif // !_TREE_NODE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Utf8/Utf8.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,4619 @@
+/*
+ * Utf8.cpp -- UTF-8 to UTF-32 conversions
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "Utf8.h"
+
+namespace {
+
+#define LEN(x)	(sizeof (x) / sizeof (x[0]))
+
+static uint32_t *
+rbsearch(uint32_t c, uint32_t *t, int n, int ne)
+{
+	uint32_t *p;
+	int m;
+
+	while (n > 1) {
+		m = n >> 1;
+		p = t + m * ne;
+
+		if (c >= p[0]) {
+			t = p;
+			n = n - m;
+		} else
+			n = m;
+	}
+
+	if (n && c >= t[0])
+		return t;
+	return 0;
+}
+
+/*
+ * The following values have been generated from Go mkrunetype.c
+ *
+ * http://golang.org/src/lib9/utf/mkrunetype.c
+ */
+
+/* {{{ Spaces */
+
+static uint32_t isspacer[] = {
+	0x0009, 0x000d,
+	0x0020, 0x0020,
+	0x0085, 0x0085,
+	0x00a0, 0x00a0,
+	0x1680, 0x1680,
+	0x2000, 0x200a,
+	0x2028, 0x2029,
+	0x202f, 0x202f,
+	0x205f, 0x205f,
+	0x3000, 0x3000,
+	0xfeff, 0xfeff,
+};
+
+/* }}} */
+
+/* {{{ Digits */
+
+static uint32_t isdigitr[] = {
+	0x0030, 0x0039,
+	0x0660, 0x0669,
+	0x06f0, 0x06f9,
+	0x07c0, 0x07c9,
+	0x0966, 0x096f,
+	0x09e6, 0x09ef,
+	0x0a66, 0x0a6f,
+	0x0ae6, 0x0aef,
+	0x0b66, 0x0b6f,
+	0x0be6, 0x0bef,
+	0x0c66, 0x0c6f,
+	0x0ce6, 0x0cef,
+	0x0d66, 0x0d6f,
+	0x0e50, 0x0e59,
+	0x0ed0, 0x0ed9,
+	0x0f20, 0x0f29,
+	0x1040, 0x1049,
+	0x1090, 0x1099,
+	0x17e0, 0x17e9,
+	0x1810, 0x1819,
+	0x1946, 0x194f,
+	0x19d0, 0x19d9,
+	0x1a80, 0x1a89,
+	0x1a90, 0x1a99,
+	0x1b50, 0x1b59,
+	0x1bb0, 0x1bb9,
+	0x1c40, 0x1c49,
+	0x1c50, 0x1c59,
+	0xa620, 0xa629,
+	0xa8d0, 0xa8d9,
+	0xa900, 0xa909,
+	0xa9d0, 0xa9d9,
+	0xaa50, 0xaa59,
+	0xabf0, 0xabf9,
+	0xff10, 0xff19,
+	0x104a0, 0x104a9,
+	0x11066, 0x1106f,
+	0x110f0, 0x110f9,
+	0x11136, 0x1113f,
+	0x111d0, 0x111d9,
+	0x116c0, 0x116c9,
+	0x1d7ce, 0x1d7ff,
+};
+
+/* }}} */
+
+/* {{{ Unicode letters */
+
+static uint32_t isalphar[] = {
+	0x0041, 0x005a,
+	0x0061, 0x007a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00f6,
+	0x00f8, 0x02c1,
+	0x02c6, 0x02d1,
+	0x02e0, 0x02e4,
+	0x0370, 0x0374,
+	0x0376, 0x0377,
+	0x037a, 0x037d,
+	0x0388, 0x038a,
+	0x038e, 0x03a1,
+	0x03a3, 0x03f5,
+	0x03f7, 0x0481,
+	0x048a, 0x0527,
+	0x0531, 0x0556,
+	0x0561, 0x0587,
+	0x05d0, 0x05ea,
+	0x05f0, 0x05f2,
+	0x0620, 0x064a,
+	0x066e, 0x066f,
+	0x0671, 0x06d3,
+	0x06e5, 0x06e6,
+	0x06ee, 0x06ef,
+	0x06fa, 0x06fc,
+	0x0712, 0x072f,
+	0x074d, 0x07a5,
+	0x07ca, 0x07ea,
+	0x07f4, 0x07f5,
+	0x0800, 0x0815,
+	0x0840, 0x0858,
+	0x08a2, 0x08ac,
+	0x0904, 0x0939,
+	0x0958, 0x0961,
+	0x0971, 0x0977,
+	0x0979, 0x097f,
+	0x0985, 0x098c,
+	0x098f, 0x0990,
+	0x0993, 0x09a8,
+	0x09aa, 0x09b0,
+	0x09b6, 0x09b9,
+	0x09dc, 0x09dd,
+	0x09df, 0x09e1,
+	0x09f0, 0x09f1,
+	0x0a05, 0x0a0a,
+	0x0a0f, 0x0a10,
+	0x0a13, 0x0a28,
+	0x0a2a, 0x0a30,
+	0x0a32, 0x0a33,
+	0x0a35, 0x0a36,
+	0x0a38, 0x0a39,
+	0x0a59, 0x0a5c,
+	0x0a72, 0x0a74,
+	0x0a85, 0x0a8d,
+	0x0a8f, 0x0a91,
+	0x0a93, 0x0aa8,
+	0x0aaa, 0x0ab0,
+	0x0ab2, 0x0ab3,
+	0x0ab5, 0x0ab9,
+	0x0ae0, 0x0ae1,
+	0x0b05, 0x0b0c,
+	0x0b0f, 0x0b10,
+	0x0b13, 0x0b28,
+	0x0b2a, 0x0b30,
+	0x0b32, 0x0b33,
+	0x0b35, 0x0b39,
+	0x0b5c, 0x0b5d,
+	0x0b5f, 0x0b61,
+	0x0b85, 0x0b8a,
+	0x0b8e, 0x0b90,
+	0x0b92, 0x0b95,
+	0x0b99, 0x0b9a,
+	0x0b9e, 0x0b9f,
+	0x0ba3, 0x0ba4,
+	0x0ba8, 0x0baa,
+	0x0bae, 0x0bb9,
+	0x0c05, 0x0c0c,
+	0x0c0e, 0x0c10,
+	0x0c12, 0x0c28,
+	0x0c2a, 0x0c33,
+	0x0c35, 0x0c39,
+	0x0c58, 0x0c59,
+	0x0c60, 0x0c61,
+	0x0c85, 0x0c8c,
+	0x0c8e, 0x0c90,
+	0x0c92, 0x0ca8,
+	0x0caa, 0x0cb3,
+	0x0cb5, 0x0cb9,
+	0x0ce0, 0x0ce1,
+	0x0cf1, 0x0cf2,
+	0x0d05, 0x0d0c,
+	0x0d0e, 0x0d10,
+	0x0d12, 0x0d3a,
+	0x0d60, 0x0d61,
+	0x0d7a, 0x0d7f,
+	0x0d85, 0x0d96,
+	0x0d9a, 0x0db1,
+	0x0db3, 0x0dbb,
+	0x0dc0, 0x0dc6,
+	0x0e01, 0x0e30,
+	0x0e32, 0x0e33,
+	0x0e40, 0x0e46,
+	0x0e81, 0x0e82,
+	0x0e87, 0x0e88,
+	0x0e94, 0x0e97,
+	0x0e99, 0x0e9f,
+	0x0ea1, 0x0ea3,
+	0x0eaa, 0x0eab,
+	0x0ead, 0x0eb0,
+	0x0eb2, 0x0eb3,
+	0x0ec0, 0x0ec4,
+	0x0edc, 0x0edf,
+	0x0f40, 0x0f47,
+	0x0f49, 0x0f6c,
+	0x0f88, 0x0f8c,
+	0x1000, 0x102a,
+	0x1050, 0x1055,
+	0x105a, 0x105d,
+	0x1065, 0x1066,
+	0x106e, 0x1070,
+	0x1075, 0x1081,
+	0x10a0, 0x10c5,
+	0x10d0, 0x10fa,
+	0x10fc, 0x1248,
+	0x124a, 0x124d,
+	0x1250, 0x1256,
+	0x125a, 0x125d,
+	0x1260, 0x1288,
+	0x128a, 0x128d,
+	0x1290, 0x12b0,
+	0x12b2, 0x12b5,
+	0x12b8, 0x12be,
+	0x12c2, 0x12c5,
+	0x12c8, 0x12d6,
+	0x12d8, 0x1310,
+	0x1312, 0x1315,
+	0x1318, 0x135a,
+	0x1380, 0x138f,
+	0x13a0, 0x13f4,
+	0x1401, 0x166c,
+	0x166f, 0x167f,
+	0x1681, 0x169a,
+	0x16a0, 0x16ea,
+	0x1700, 0x170c,
+	0x170e, 0x1711,
+	0x1720, 0x1731,
+	0x1740, 0x1751,
+	0x1760, 0x176c,
+	0x176e, 0x1770,
+	0x1780, 0x17b3,
+	0x1820, 0x1877,
+	0x1880, 0x18a8,
+	0x18b0, 0x18f5,
+	0x1900, 0x191c,
+	0x1950, 0x196d,
+	0x1970, 0x1974,
+	0x1980, 0x19ab,
+	0x19c1, 0x19c7,
+	0x1a00, 0x1a16,
+	0x1a20, 0x1a54,
+	0x1b05, 0x1b33,
+	0x1b45, 0x1b4b,
+	0x1b83, 0x1ba0,
+	0x1bae, 0x1baf,
+	0x1bba, 0x1be5,
+	0x1c00, 0x1c23,
+	0x1c4d, 0x1c4f,
+	0x1c5a, 0x1c7d,
+	0x1ce9, 0x1cec,
+	0x1cee, 0x1cf1,
+	0x1cf5, 0x1cf6,
+	0x1d00, 0x1dbf,
+	0x1e00, 0x1f15,
+	0x1f18, 0x1f1d,
+	0x1f20, 0x1f45,
+	0x1f48, 0x1f4d,
+	0x1f50, 0x1f57,
+	0x1f5f, 0x1f7d,
+	0x1f80, 0x1fb4,
+	0x1fb6, 0x1fbc,
+	0x1fc2, 0x1fc4,
+	0x1fc6, 0x1fcc,
+	0x1fd0, 0x1fd3,
+	0x1fd6, 0x1fdb,
+	0x1fe0, 0x1fec,
+	0x1ff2, 0x1ff4,
+	0x1ff6, 0x1ffc,
+	0x2090, 0x209c,
+	0x210a, 0x2113,
+	0x2119, 0x211d,
+	0x212a, 0x212d,
+	0x212f, 0x2139,
+	0x213c, 0x213f,
+	0x2145, 0x2149,
+	0x2183, 0x2184,
+	0x2c00, 0x2c2e,
+	0x2c30, 0x2c5e,
+	0x2c60, 0x2ce4,
+	0x2ceb, 0x2cee,
+	0x2cf2, 0x2cf3,
+	0x2d00, 0x2d25,
+	0x2d30, 0x2d67,
+	0x2d80, 0x2d96,
+	0x2da0, 0x2da6,
+	0x2da8, 0x2dae,
+	0x2db0, 0x2db6,
+	0x2db8, 0x2dbe,
+	0x2dc0, 0x2dc6,
+	0x2dc8, 0x2dce,
+	0x2dd0, 0x2dd6,
+	0x2dd8, 0x2dde,
+	0x3005, 0x3006,
+	0x3031, 0x3035,
+	0x303b, 0x303c,
+	0x3041, 0x3096,
+	0x309d, 0x309f,
+	0x30a1, 0x30fa,
+	0x30fc, 0x30ff,
+	0x3105, 0x312d,
+	0x3131, 0x318e,
+	0x31a0, 0x31ba,
+	0x31f0, 0x31ff,
+	0x3400, 0x4db5,
+	0x4e00, 0x9fcc,
+	0xa000, 0xa48c,
+	0xa4d0, 0xa4fd,
+	0xa500, 0xa60c,
+	0xa610, 0xa61f,
+	0xa62a, 0xa62b,
+	0xa640, 0xa66e,
+	0xa67f, 0xa697,
+	0xa6a0, 0xa6e5,
+	0xa717, 0xa71f,
+	0xa722, 0xa788,
+	0xa78b, 0xa78e,
+	0xa790, 0xa793,
+	0xa7a0, 0xa7aa,
+	0xa7f8, 0xa801,
+	0xa803, 0xa805,
+	0xa807, 0xa80a,
+	0xa80c, 0xa822,
+	0xa840, 0xa873,
+	0xa882, 0xa8b3,
+	0xa8f2, 0xa8f7,
+	0xa90a, 0xa925,
+	0xa930, 0xa946,
+	0xa960, 0xa97c,
+	0xa984, 0xa9b2,
+	0xaa00, 0xaa28,
+	0xaa40, 0xaa42,
+	0xaa44, 0xaa4b,
+	0xaa60, 0xaa76,
+	0xaa80, 0xaaaf,
+	0xaab5, 0xaab6,
+	0xaab9, 0xaabd,
+	0xaadb, 0xaadd,
+	0xaae0, 0xaaea,
+	0xaaf2, 0xaaf4,
+	0xab01, 0xab06,
+	0xab09, 0xab0e,
+	0xab11, 0xab16,
+	0xab20, 0xab26,
+	0xab28, 0xab2e,
+	0xabc0, 0xabe2,
+	0xac00, 0xd7a3,
+	0xd7b0, 0xd7c6,
+	0xd7cb, 0xd7fb,
+	0xf900, 0xfa6d,
+	0xfa70, 0xfad9,
+	0xfb00, 0xfb06,
+	0xfb13, 0xfb17,
+	0xfb1f, 0xfb28,
+	0xfb2a, 0xfb36,
+	0xfb38, 0xfb3c,
+	0xfb40, 0xfb41,
+	0xfb43, 0xfb44,
+	0xfb46, 0xfbb1,
+	0xfbd3, 0xfd3d,
+	0xfd50, 0xfd8f,
+	0xfd92, 0xfdc7,
+	0xfdf0, 0xfdfb,
+	0xfe70, 0xfe74,
+	0xfe76, 0xfefc,
+	0xff21, 0xff3a,
+	0xff41, 0xff5a,
+	0xff66, 0xffbe,
+	0xffc2, 0xffc7,
+	0xffca, 0xffcf,
+	0xffd2, 0xffd7,
+	0xffda, 0xffdc,
+	0x10000, 0x1000b,
+	0x1000d, 0x10026,
+	0x10028, 0x1003a,
+	0x1003c, 0x1003d,
+	0x1003f, 0x1004d,
+	0x10050, 0x1005d,
+	0x10080, 0x100fa,
+	0x10280, 0x1029c,
+	0x102a0, 0x102d0,
+	0x10300, 0x1031e,
+	0x10330, 0x10340,
+	0x10342, 0x10349,
+	0x10380, 0x1039d,
+	0x103a0, 0x103c3,
+	0x103c8, 0x103cf,
+	0x10400, 0x1049d,
+	0x10800, 0x10805,
+	0x1080a, 0x10835,
+	0x10837, 0x10838,
+	0x1083f, 0x10855,
+	0x10900, 0x10915,
+	0x10920, 0x10939,
+	0x10980, 0x109b7,
+	0x109be, 0x109bf,
+	0x10a10, 0x10a13,
+	0x10a15, 0x10a17,
+	0x10a19, 0x10a33,
+	0x10a60, 0x10a7c,
+	0x10b00, 0x10b35,
+	0x10b40, 0x10b55,
+	0x10b60, 0x10b72,
+	0x10c00, 0x10c48,
+	0x11003, 0x11037,
+	0x11083, 0x110af,
+	0x110d0, 0x110e8,
+	0x11103, 0x11126,
+	0x11183, 0x111b2,
+	0x111c1, 0x111c4,
+	0x11680, 0x116aa,
+	0x12000, 0x1236e,
+	0x13000, 0x1342e,
+	0x16800, 0x16a38,
+	0x16f00, 0x16f44,
+	0x16f93, 0x16f9f,
+	0x1b000, 0x1b001,
+	0x1d400, 0x1d454,
+	0x1d456, 0x1d49c,
+	0x1d49e, 0x1d49f,
+	0x1d4a5, 0x1d4a6,
+	0x1d4a9, 0x1d4ac,
+	0x1d4ae, 0x1d4b9,
+	0x1d4bd, 0x1d4c3,
+	0x1d4c5, 0x1d505,
+	0x1d507, 0x1d50a,
+	0x1d50d, 0x1d514,
+	0x1d516, 0x1d51c,
+	0x1d51e, 0x1d539,
+	0x1d53b, 0x1d53e,
+	0x1d540, 0x1d544,
+	0x1d54a, 0x1d550,
+	0x1d552, 0x1d6a5,
+	0x1d6a8, 0x1d6c0,
+	0x1d6c2, 0x1d6da,
+	0x1d6dc, 0x1d6fa,
+	0x1d6fc, 0x1d714,
+	0x1d716, 0x1d734,
+	0x1d736, 0x1d74e,
+	0x1d750, 0x1d76e,
+	0x1d770, 0x1d788,
+	0x1d78a, 0x1d7a8,
+	0x1d7aa, 0x1d7c2,
+	0x1d7c4, 0x1d7cb,
+	0x1ee00, 0x1ee03,
+	0x1ee05, 0x1ee1f,
+	0x1ee21, 0x1ee22,
+	0x1ee29, 0x1ee32,
+	0x1ee34, 0x1ee37,
+	0x1ee4d, 0x1ee4f,
+	0x1ee51, 0x1ee52,
+	0x1ee61, 0x1ee62,
+	0x1ee67, 0x1ee6a,
+	0x1ee6c, 0x1ee72,
+	0x1ee74, 0x1ee77,
+	0x1ee79, 0x1ee7c,
+	0x1ee80, 0x1ee89,
+	0x1ee8b, 0x1ee9b,
+	0x1eea1, 0x1eea3,
+	0x1eea5, 0x1eea9,
+	0x1eeab, 0x1eebb,
+	0x20000, 0x2a6d6,
+	0x2a700, 0x2b734,
+	0x2b740, 0x2b81d,
+	0x2f800, 0x2fa1d,
+};
+
+/* }}} */
+
+/* {{{ Letters */
+
+static uint32_t isalphas[] = {
+	0x00aa,
+	0x00b5,
+	0x00ba,
+	0x02ec,
+	0x02ee,
+	0x0386,
+	0x038c,
+	0x0559,
+	0x06d5,
+	0x06ff,
+	0x0710,
+	0x07b1,
+	0x07fa,
+	0x081a,
+	0x0824,
+	0x0828,
+	0x08a0,
+	0x093d,
+	0x0950,
+	0x09b2,
+	0x09bd,
+	0x09ce,
+	0x0a5e,
+	0x0abd,
+	0x0ad0,
+	0x0b3d,
+	0x0b71,
+	0x0b83,
+	0x0b9c,
+	0x0bd0,
+	0x0c3d,
+	0x0cbd,
+	0x0cde,
+	0x0d3d,
+	0x0d4e,
+	0x0dbd,
+	0x0e84,
+	0x0e8a,
+	0x0e8d,
+	0x0ea5,
+	0x0ea7,
+	0x0ebd,
+	0x0ec6,
+	0x0f00,
+	0x103f,
+	0x1061,
+	0x108e,
+	0x10c7,
+	0x10cd,
+	0x1258,
+	0x12c0,
+	0x17d7,
+	0x17dc,
+	0x18aa,
+	0x1aa7,
+	0x1f59,
+	0x1f5b,
+	0x1f5d,
+	0x1fbe,
+	0x2071,
+	0x207f,
+	0x2102,
+	0x2107,
+	0x2115,
+	0x2124,
+	0x2126,
+	0x2128,
+	0x214e,
+	0x2d27,
+	0x2d2d,
+	0x2d6f,
+	0x2e2f,
+	0xa8fb,
+	0xa9cf,
+	0xaa7a,
+	0xaab1,
+	0xaac0,
+	0xaac2,
+	0xfb1d,
+	0xfb3e,
+	0x10808,
+	0x1083c,
+	0x10a00,
+	0x16f50,
+	0x1d4a2,
+	0x1d4bb,
+	0x1d546,
+	0x1ee24,
+	0x1ee27,
+	0x1ee39,
+	0x1ee3b,
+	0x1ee42,
+	0x1ee47,
+	0x1ee49,
+	0x1ee4b,
+	0x1ee54,
+	0x1ee57,
+	0x1ee59,
+	0x1ee5b,
+	0x1ee5d,
+	0x1ee5f,
+	0x1ee64,
+	0x1ee7e,
+};
+
+/* }}} */
+
+/* {{{ Unicode upper */
+
+static uint32_t isupperr[] = {
+	0x0041, 0x005a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00de,
+	0x0178, 0x0179,
+	0x0181, 0x0182,
+	0x0186, 0x0187,
+	0x0189, 0x018b,
+	0x018e, 0x0191,
+	0x0193, 0x0194,
+	0x0196, 0x0198,
+	0x019c, 0x019d,
+	0x019f, 0x01a0,
+	0x01a6, 0x01a7,
+	0x01ae, 0x01af,
+	0x01b1, 0x01b3,
+	0x01b7, 0x01b8,
+	0x01f6, 0x01f8,
+	0x023a, 0x023b,
+	0x023d, 0x023e,
+	0x0243, 0x0246,
+	0x0388, 0x038a,
+	0x038e, 0x038f,
+	0x0391, 0x03a1,
+	0x03a3, 0x03ab,
+	0x03d2, 0x03d4,
+	0x03f9, 0x03fa,
+	0x03fd, 0x042f,
+	0x04c0, 0x04c1,
+	0x0531, 0x0556,
+	0x10a0, 0x10c5,
+	0x1f08, 0x1f0f,
+	0x1f18, 0x1f1d,
+	0x1f28, 0x1f2f,
+	0x1f38, 0x1f3f,
+	0x1f48, 0x1f4d,
+	0x1f68, 0x1f6f,
+	0x1f88, 0x1f8f,
+	0x1f98, 0x1f9f,
+	0x1fa8, 0x1faf,
+	0x1fb8, 0x1fbc,
+	0x1fc8, 0x1fcc,
+	0x1fd8, 0x1fdb,
+	0x1fe8, 0x1fec,
+	0x1ff8, 0x1ffc,
+	0x210b, 0x210d,
+	0x2110, 0x2112,
+	0x2119, 0x211d,
+	0x212a, 0x212d,
+	0x2130, 0x2133,
+	0x213e, 0x213f,
+	0x2160, 0x216f,
+	0x24b6, 0x24cf,
+	0x2c00, 0x2c2e,
+	0x2c62, 0x2c64,
+	0x2c6d, 0x2c70,
+	0x2c7e, 0x2c80,
+	0xa77d, 0xa77e,
+	0xff21, 0xff3a,
+	0x10400, 0x10427,
+	0x1d400, 0x1d419,
+	0x1d434, 0x1d44d,
+	0x1d468, 0x1d481,
+	0x1d49e, 0x1d49f,
+	0x1d4a5, 0x1d4a6,
+	0x1d4a9, 0x1d4ac,
+	0x1d4ae, 0x1d4b5,
+	0x1d4d0, 0x1d4e9,
+	0x1d504, 0x1d505,
+	0x1d507, 0x1d50a,
+	0x1d50d, 0x1d514,
+	0x1d516, 0x1d51c,
+	0x1d538, 0x1d539,
+	0x1d53b, 0x1d53e,
+	0x1d540, 0x1d544,
+	0x1d54a, 0x1d550,
+	0x1d56c, 0x1d585,
+	0x1d5a0, 0x1d5b9,
+	0x1d5d4, 0x1d5ed,
+	0x1d608, 0x1d621,
+	0x1d63c, 0x1d655,
+	0x1d670, 0x1d689,
+	0x1d6a8, 0x1d6c0,
+	0x1d6e2, 0x1d6fa,
+	0x1d71c, 0x1d734,
+	0x1d756, 0x1d76e,
+	0x1d790, 0x1d7a8,
+};
+
+/* }}} */
+
+/* {{{ Upper */
+
+static uint32_t isuppers[] = {
+	0x0100,
+	0x0102,
+	0x0104,
+	0x0106,
+	0x0108,
+	0x010a,
+	0x010c,
+	0x010e,
+	0x0110,
+	0x0112,
+	0x0114,
+	0x0116,
+	0x0118,
+	0x011a,
+	0x011c,
+	0x011e,
+	0x0120,
+	0x0122,
+	0x0124,
+	0x0126,
+	0x0128,
+	0x012a,
+	0x012c,
+	0x012e,
+	0x0130,
+	0x0132,
+	0x0134,
+	0x0136,
+	0x0139,
+	0x013b,
+	0x013d,
+	0x013f,
+	0x0141,
+	0x0143,
+	0x0145,
+	0x0147,
+	0x014a,
+	0x014c,
+	0x014e,
+	0x0150,
+	0x0152,
+	0x0154,
+	0x0156,
+	0x0158,
+	0x015a,
+	0x015c,
+	0x015e,
+	0x0160,
+	0x0162,
+	0x0164,
+	0x0166,
+	0x0168,
+	0x016a,
+	0x016c,
+	0x016e,
+	0x0170,
+	0x0172,
+	0x0174,
+	0x0176,
+	0x017b,
+	0x017d,
+	0x0184,
+	0x01a2,
+	0x01a4,
+	0x01a9,
+	0x01ac,
+	0x01b5,
+	0x01bc,
+	0x01c4,
+	0x01c7,
+	0x01ca,
+	0x01cd,
+	0x01cf,
+	0x01d1,
+	0x01d3,
+	0x01d5,
+	0x01d7,
+	0x01d9,
+	0x01db,
+	0x01de,
+	0x01e0,
+	0x01e2,
+	0x01e4,
+	0x01e6,
+	0x01e8,
+	0x01ea,
+	0x01ec,
+	0x01ee,
+	0x01f1,
+	0x01f4,
+	0x01fa,
+	0x01fc,
+	0x01fe,
+	0x0200,
+	0x0202,
+	0x0204,
+	0x0206,
+	0x0208,
+	0x020a,
+	0x020c,
+	0x020e,
+	0x0210,
+	0x0212,
+	0x0214,
+	0x0216,
+	0x0218,
+	0x021a,
+	0x021c,
+	0x021e,
+	0x0220,
+	0x0222,
+	0x0224,
+	0x0226,
+	0x0228,
+	0x022a,
+	0x022c,
+	0x022e,
+	0x0230,
+	0x0232,
+	0x0241,
+	0x0248,
+	0x024a,
+	0x024c,
+	0x024e,
+	0x0370,
+	0x0372,
+	0x0376,
+	0x0386,
+	0x038c,
+	0x03cf,
+	0x03d8,
+	0x03da,
+	0x03dc,
+	0x03de,
+	0x03e0,
+	0x03e2,
+	0x03e4,
+	0x03e6,
+	0x03e8,
+	0x03ea,
+	0x03ec,
+	0x03ee,
+	0x03f4,
+	0x03f7,
+	0x0460,
+	0x0462,
+	0x0464,
+	0x0466,
+	0x0468,
+	0x046a,
+	0x046c,
+	0x046e,
+	0x0470,
+	0x0472,
+	0x0474,
+	0x0476,
+	0x0478,
+	0x047a,
+	0x047c,
+	0x047e,
+	0x0480,
+	0x048a,
+	0x048c,
+	0x048e,
+	0x0490,
+	0x0492,
+	0x0494,
+	0x0496,
+	0x0498,
+	0x049a,
+	0x049c,
+	0x049e,
+	0x04a0,
+	0x04a2,
+	0x04a4,
+	0x04a6,
+	0x04a8,
+	0x04aa,
+	0x04ac,
+	0x04ae,
+	0x04b0,
+	0x04b2,
+	0x04b4,
+	0x04b6,
+	0x04b8,
+	0x04ba,
+	0x04bc,
+	0x04be,
+	0x04c3,
+	0x04c5,
+	0x04c7,
+	0x04c9,
+	0x04cb,
+	0x04cd,
+	0x04d0,
+	0x04d2,
+	0x04d4,
+	0x04d6,
+	0x04d8,
+	0x04da,
+	0x04dc,
+	0x04de,
+	0x04e0,
+	0x04e2,
+	0x04e4,
+	0x04e6,
+	0x04e8,
+	0x04ea,
+	0x04ec,
+	0x04ee,
+	0x04f0,
+	0x04f2,
+	0x04f4,
+	0x04f6,
+	0x04f8,
+	0x04fa,
+	0x04fc,
+	0x04fe,
+	0x0500,
+	0x0502,
+	0x0504,
+	0x0506,
+	0x0508,
+	0x050a,
+	0x050c,
+	0x050e,
+	0x0510,
+	0x0512,
+	0x0514,
+	0x0516,
+	0x0518,
+	0x051a,
+	0x051c,
+	0x051e,
+	0x0520,
+	0x0522,
+	0x0524,
+	0x0526,
+	0x10c7,
+	0x10cd,
+	0x1e00,
+	0x1e02,
+	0x1e04,
+	0x1e06,
+	0x1e08,
+	0x1e0a,
+	0x1e0c,
+	0x1e0e,
+	0x1e10,
+	0x1e12,
+	0x1e14,
+	0x1e16,
+	0x1e18,
+	0x1e1a,
+	0x1e1c,
+	0x1e1e,
+	0x1e20,
+	0x1e22,
+	0x1e24,
+	0x1e26,
+	0x1e28,
+	0x1e2a,
+	0x1e2c,
+	0x1e2e,
+	0x1e30,
+	0x1e32,
+	0x1e34,
+	0x1e36,
+	0x1e38,
+	0x1e3a,
+	0x1e3c,
+	0x1e3e,
+	0x1e40,
+	0x1e42,
+	0x1e44,
+	0x1e46,
+	0x1e48,
+	0x1e4a,
+	0x1e4c,
+	0x1e4e,
+	0x1e50,
+	0x1e52,
+	0x1e54,
+	0x1e56,
+	0x1e58,
+	0x1e5a,
+	0x1e5c,
+	0x1e5e,
+	0x1e60,
+	0x1e62,
+	0x1e64,
+	0x1e66,
+	0x1e68,
+	0x1e6a,
+	0x1e6c,
+	0x1e6e,
+	0x1e70,
+	0x1e72,
+	0x1e74,
+	0x1e76,
+	0x1e78,
+	0x1e7a,
+	0x1e7c,
+	0x1e7e,
+	0x1e80,
+	0x1e82,
+	0x1e84,
+	0x1e86,
+	0x1e88,
+	0x1e8a,
+	0x1e8c,
+	0x1e8e,
+	0x1e90,
+	0x1e92,
+	0x1e94,
+	0x1e9e,
+	0x1ea0,
+	0x1ea2,
+	0x1ea4,
+	0x1ea6,
+	0x1ea8,
+	0x1eaa,
+	0x1eac,
+	0x1eae,
+	0x1eb0,
+	0x1eb2,
+	0x1eb4,
+	0x1eb6,
+	0x1eb8,
+	0x1eba,
+	0x1ebc,
+	0x1ebe,
+	0x1ec0,
+	0x1ec2,
+	0x1ec4,
+	0x1ec6,
+	0x1ec8,
+	0x1eca,
+	0x1ecc,
+	0x1ece,
+	0x1ed0,
+	0x1ed2,
+	0x1ed4,
+	0x1ed6,
+	0x1ed8,
+	0x1eda,
+	0x1edc,
+	0x1ede,
+	0x1ee0,
+	0x1ee2,
+	0x1ee4,
+	0x1ee6,
+	0x1ee8,
+	0x1eea,
+	0x1eec,
+	0x1eee,
+	0x1ef0,
+	0x1ef2,
+	0x1ef4,
+	0x1ef6,
+	0x1ef8,
+	0x1efa,
+	0x1efc,
+	0x1efe,
+	0x1f59,
+	0x1f5b,
+	0x1f5d,
+	0x1f5f,
+	0x2102,
+	0x2107,
+	0x2115,
+	0x2124,
+	0x2126,
+	0x2128,
+	0x2145,
+	0x2183,
+	0x2c60,
+	0x2c67,
+	0x2c69,
+	0x2c6b,
+	0x2c72,
+	0x2c75,
+	0x2c82,
+	0x2c84,
+	0x2c86,
+	0x2c88,
+	0x2c8a,
+	0x2c8c,
+	0x2c8e,
+	0x2c90,
+	0x2c92,
+	0x2c94,
+	0x2c96,
+	0x2c98,
+	0x2c9a,
+	0x2c9c,
+	0x2c9e,
+	0x2ca0,
+	0x2ca2,
+	0x2ca4,
+	0x2ca6,
+	0x2ca8,
+	0x2caa,
+	0x2cac,
+	0x2cae,
+	0x2cb0,
+	0x2cb2,
+	0x2cb4,
+	0x2cb6,
+	0x2cb8,
+	0x2cba,
+	0x2cbc,
+	0x2cbe,
+	0x2cc0,
+	0x2cc2,
+	0x2cc4,
+	0x2cc6,
+	0x2cc8,
+	0x2cca,
+	0x2ccc,
+	0x2cce,
+	0x2cd0,
+	0x2cd2,
+	0x2cd4,
+	0x2cd6,
+	0x2cd8,
+	0x2cda,
+	0x2cdc,
+	0x2cde,
+	0x2ce0,
+	0x2ce2,
+	0x2ceb,
+	0x2ced,
+	0x2cf2,
+	0xa640,
+	0xa642,
+	0xa644,
+	0xa646,
+	0xa648,
+	0xa64a,
+	0xa64c,
+	0xa64e,
+	0xa650,
+	0xa652,
+	0xa654,
+	0xa656,
+	0xa658,
+	0xa65a,
+	0xa65c,
+	0xa65e,
+	0xa660,
+	0xa662,
+	0xa664,
+	0xa666,
+	0xa668,
+	0xa66a,
+	0xa66c,
+	0xa680,
+	0xa682,
+	0xa684,
+	0xa686,
+	0xa688,
+	0xa68a,
+	0xa68c,
+	0xa68e,
+	0xa690,
+	0xa692,
+	0xa694,
+	0xa696,
+	0xa722,
+	0xa724,
+	0xa726,
+	0xa728,
+	0xa72a,
+	0xa72c,
+	0xa72e,
+	0xa732,
+	0xa734,
+	0xa736,
+	0xa738,
+	0xa73a,
+	0xa73c,
+	0xa73e,
+	0xa740,
+	0xa742,
+	0xa744,
+	0xa746,
+	0xa748,
+	0xa74a,
+	0xa74c,
+	0xa74e,
+	0xa750,
+	0xa752,
+	0xa754,
+	0xa756,
+	0xa758,
+	0xa75a,
+	0xa75c,
+	0xa75e,
+	0xa760,
+	0xa762,
+	0xa764,
+	0xa766,
+	0xa768,
+	0xa76a,
+	0xa76c,
+	0xa76e,
+	0xa779,
+	0xa77b,
+	0xa780,
+	0xa782,
+	0xa784,
+	0xa786,
+	0xa78b,
+	0xa78d,
+	0xa790,
+	0xa792,
+	0xa7a0,
+	0xa7a2,
+	0xa7a4,
+	0xa7a6,
+	0xa7a8,
+	0xa7aa,
+	0x1d49c,
+	0x1d4a2,
+	0x1d546,
+	0x1d7ca,
+};
+
+/* }}} */
+
+/* {{{ Unicode lower */
+
+static uint32_t islowerr[] = {
+	0x0061, 0x007a,
+	0x00df, 0x00f6,
+	0x00f8, 0x00ff,
+	0x0137, 0x0138,
+	0x0148, 0x0149,
+	0x017e, 0x0180,
+	0x018c, 0x018d,
+	0x0199, 0x019b,
+	0x01aa, 0x01ab,
+	0x01b9, 0x01ba,
+	0x01bd, 0x01bf,
+	0x01dc, 0x01dd,
+	0x01ef, 0x01f0,
+	0x0233, 0x0239,
+	0x023f, 0x0240,
+	0x024f, 0x0293,
+	0x0295, 0x02af,
+	0x037b, 0x037d,
+	0x03ac, 0x03ce,
+	0x03d0, 0x03d1,
+	0x03d5, 0x03d7,
+	0x03ef, 0x03f3,
+	0x03fb, 0x03fc,
+	0x0430, 0x045f,
+	0x04ce, 0x04cf,
+	0x0561, 0x0587,
+	0x1d00, 0x1d2b,
+	0x1d6b, 0x1d77,
+	0x1d79, 0x1d9a,
+	0x1e95, 0x1e9d,
+	0x1eff, 0x1f07,
+	0x1f10, 0x1f15,
+	0x1f20, 0x1f27,
+	0x1f30, 0x1f37,
+	0x1f40, 0x1f45,
+	0x1f50, 0x1f57,
+	0x1f60, 0x1f67,
+	0x1f70, 0x1f7d,
+	0x1f80, 0x1f87,
+	0x1f90, 0x1f97,
+	0x1fa0, 0x1fa7,
+	0x1fb0, 0x1fb4,
+	0x1fb6, 0x1fb7,
+	0x1fc2, 0x1fc4,
+	0x1fc6, 0x1fc7,
+	0x1fd0, 0x1fd3,
+	0x1fd6, 0x1fd7,
+	0x1fe0, 0x1fe7,
+	0x1ff2, 0x1ff4,
+	0x1ff6, 0x1ff7,
+	0x210e, 0x210f,
+	0x213c, 0x213d,
+	0x2146, 0x2149,
+	0x2170, 0x217f,
+	0x24d0, 0x24e9,
+	0x2c30, 0x2c5e,
+	0x2c65, 0x2c66,
+	0x2c73, 0x2c74,
+	0x2c76, 0x2c7b,
+	0x2ce3, 0x2ce4,
+	0x2d00, 0x2d25,
+	0xa72f, 0xa731,
+	0xa771, 0xa778,
+	0xfb00, 0xfb06,
+	0xfb13, 0xfb17,
+	0xff41, 0xff5a,
+	0x10428, 0x1044f,
+	0x1d41a, 0x1d433,
+	0x1d44e, 0x1d454,
+	0x1d456, 0x1d467,
+	0x1d482, 0x1d49b,
+	0x1d4b6, 0x1d4b9,
+	0x1d4bd, 0x1d4c3,
+	0x1d4c5, 0x1d4cf,
+	0x1d4ea, 0x1d503,
+	0x1d51e, 0x1d537,
+	0x1d552, 0x1d56b,
+	0x1d586, 0x1d59f,
+	0x1d5ba, 0x1d5d3,
+	0x1d5ee, 0x1d607,
+	0x1d622, 0x1d63b,
+	0x1d656, 0x1d66f,
+	0x1d68a, 0x1d6a5,
+	0x1d6c2, 0x1d6da,
+	0x1d6dc, 0x1d6e1,
+	0x1d6fc, 0x1d714,
+	0x1d716, 0x1d71b,
+	0x1d736, 0x1d74e,
+	0x1d750, 0x1d755,
+	0x1d770, 0x1d788,
+	0x1d78a, 0x1d78f,
+	0x1d7aa, 0x1d7c2,
+	0x1d7c4, 0x1d7c9,
+};
+
+/* }}} */
+
+/* {{{ Lower */
+
+static uint32_t islowers[] = {
+	0x00b5,
+	0x0101,
+	0x0103,
+	0x0105,
+	0x0107,
+	0x0109,
+	0x010b,
+	0x010d,
+	0x010f,
+	0x0111,
+	0x0113,
+	0x0115,
+	0x0117,
+	0x0119,
+	0x011b,
+	0x011d,
+	0x011f,
+	0x0121,
+	0x0123,
+	0x0125,
+	0x0127,
+	0x0129,
+	0x012b,
+	0x012d,
+	0x012f,
+	0x0131,
+	0x0133,
+	0x0135,
+	0x013a,
+	0x013c,
+	0x013e,
+	0x0140,
+	0x0142,
+	0x0144,
+	0x0146,
+	0x014b,
+	0x014d,
+	0x014f,
+	0x0151,
+	0x0153,
+	0x0155,
+	0x0157,
+	0x0159,
+	0x015b,
+	0x015d,
+	0x015f,
+	0x0161,
+	0x0163,
+	0x0165,
+	0x0167,
+	0x0169,
+	0x016b,
+	0x016d,
+	0x016f,
+	0x0171,
+	0x0173,
+	0x0175,
+	0x0177,
+	0x017a,
+	0x017c,
+	0x0183,
+	0x0185,
+	0x0188,
+	0x0192,
+	0x0195,
+	0x019e,
+	0x01a1,
+	0x01a3,
+	0x01a5,
+	0x01a8,
+	0x01ad,
+	0x01b0,
+	0x01b4,
+	0x01b6,
+	0x01c6,
+	0x01c9,
+	0x01cc,
+	0x01ce,
+	0x01d0,
+	0x01d2,
+	0x01d4,
+	0x01d6,
+	0x01d8,
+	0x01da,
+	0x01df,
+	0x01e1,
+	0x01e3,
+	0x01e5,
+	0x01e7,
+	0x01e9,
+	0x01eb,
+	0x01ed,
+	0x01f3,
+	0x01f5,
+	0x01f9,
+	0x01fb,
+	0x01fd,
+	0x01ff,
+	0x0201,
+	0x0203,
+	0x0205,
+	0x0207,
+	0x0209,
+	0x020b,
+	0x020d,
+	0x020f,
+	0x0211,
+	0x0213,
+	0x0215,
+	0x0217,
+	0x0219,
+	0x021b,
+	0x021d,
+	0x021f,
+	0x0221,
+	0x0223,
+	0x0225,
+	0x0227,
+	0x0229,
+	0x022b,
+	0x022d,
+	0x022f,
+	0x0231,
+	0x023c,
+	0x0242,
+	0x0247,
+	0x0249,
+	0x024b,
+	0x024d,
+	0x0371,
+	0x0373,
+	0x0377,
+	0x0390,
+	0x03d9,
+	0x03db,
+	0x03dd,
+	0x03df,
+	0x03e1,
+	0x03e3,
+	0x03e5,
+	0x03e7,
+	0x03e9,
+	0x03eb,
+	0x03ed,
+	0x03f5,
+	0x03f8,
+	0x0461,
+	0x0463,
+	0x0465,
+	0x0467,
+	0x0469,
+	0x046b,
+	0x046d,
+	0x046f,
+	0x0471,
+	0x0473,
+	0x0475,
+	0x0477,
+	0x0479,
+	0x047b,
+	0x047d,
+	0x047f,
+	0x0481,
+	0x048b,
+	0x048d,
+	0x048f,
+	0x0491,
+	0x0493,
+	0x0495,
+	0x0497,
+	0x0499,
+	0x049b,
+	0x049d,
+	0x049f,
+	0x04a1,
+	0x04a3,
+	0x04a5,
+	0x04a7,
+	0x04a9,
+	0x04ab,
+	0x04ad,
+	0x04af,
+	0x04b1,
+	0x04b3,
+	0x04b5,
+	0x04b7,
+	0x04b9,
+	0x04bb,
+	0x04bd,
+	0x04bf,
+	0x04c2,
+	0x04c4,
+	0x04c6,
+	0x04c8,
+	0x04ca,
+	0x04cc,
+	0x04d1,
+	0x04d3,
+	0x04d5,
+	0x04d7,
+	0x04d9,
+	0x04db,
+	0x04dd,
+	0x04df,
+	0x04e1,
+	0x04e3,
+	0x04e5,
+	0x04e7,
+	0x04e9,
+	0x04eb,
+	0x04ed,
+	0x04ef,
+	0x04f1,
+	0x04f3,
+	0x04f5,
+	0x04f7,
+	0x04f9,
+	0x04fb,
+	0x04fd,
+	0x04ff,
+	0x0501,
+	0x0503,
+	0x0505,
+	0x0507,
+	0x0509,
+	0x050b,
+	0x050d,
+	0x050f,
+	0x0511,
+	0x0513,
+	0x0515,
+	0x0517,
+	0x0519,
+	0x051b,
+	0x051d,
+	0x051f,
+	0x0521,
+	0x0523,
+	0x0525,
+	0x0527,
+	0x1e01,
+	0x1e03,
+	0x1e05,
+	0x1e07,
+	0x1e09,
+	0x1e0b,
+	0x1e0d,
+	0x1e0f,
+	0x1e11,
+	0x1e13,
+	0x1e15,
+	0x1e17,
+	0x1e19,
+	0x1e1b,
+	0x1e1d,
+	0x1e1f,
+	0x1e21,
+	0x1e23,
+	0x1e25,
+	0x1e27,
+	0x1e29,
+	0x1e2b,
+	0x1e2d,
+	0x1e2f,
+	0x1e31,
+	0x1e33,
+	0x1e35,
+	0x1e37,
+	0x1e39,
+	0x1e3b,
+	0x1e3d,
+	0x1e3f,
+	0x1e41,
+	0x1e43,
+	0x1e45,
+	0x1e47,
+	0x1e49,
+	0x1e4b,
+	0x1e4d,
+	0x1e4f,
+	0x1e51,
+	0x1e53,
+	0x1e55,
+	0x1e57,
+	0x1e59,
+	0x1e5b,
+	0x1e5d,
+	0x1e5f,
+	0x1e61,
+	0x1e63,
+	0x1e65,
+	0x1e67,
+	0x1e69,
+	0x1e6b,
+	0x1e6d,
+	0x1e6f,
+	0x1e71,
+	0x1e73,
+	0x1e75,
+	0x1e77,
+	0x1e79,
+	0x1e7b,
+	0x1e7d,
+	0x1e7f,
+	0x1e81,
+	0x1e83,
+	0x1e85,
+	0x1e87,
+	0x1e89,
+	0x1e8b,
+	0x1e8d,
+	0x1e8f,
+	0x1e91,
+	0x1e93,
+	0x1e9f,
+	0x1ea1,
+	0x1ea3,
+	0x1ea5,
+	0x1ea7,
+	0x1ea9,
+	0x1eab,
+	0x1ead,
+	0x1eaf,
+	0x1eb1,
+	0x1eb3,
+	0x1eb5,
+	0x1eb7,
+	0x1eb9,
+	0x1ebb,
+	0x1ebd,
+	0x1ebf,
+	0x1ec1,
+	0x1ec3,
+	0x1ec5,
+	0x1ec7,
+	0x1ec9,
+	0x1ecb,
+	0x1ecd,
+	0x1ecf,
+	0x1ed1,
+	0x1ed3,
+	0x1ed5,
+	0x1ed7,
+	0x1ed9,
+	0x1edb,
+	0x1edd,
+	0x1edf,
+	0x1ee1,
+	0x1ee3,
+	0x1ee5,
+	0x1ee7,
+	0x1ee9,
+	0x1eeb,
+	0x1eed,
+	0x1eef,
+	0x1ef1,
+	0x1ef3,
+	0x1ef5,
+	0x1ef7,
+	0x1ef9,
+	0x1efb,
+	0x1efd,
+	0x1fbe,
+	0x210a,
+	0x2113,
+	0x212f,
+	0x2134,
+	0x2139,
+	0x214e,
+	0x2184,
+	0x2c61,
+	0x2c68,
+	0x2c6a,
+	0x2c6c,
+	0x2c71,
+	0x2c81,
+	0x2c83,
+	0x2c85,
+	0x2c87,
+	0x2c89,
+	0x2c8b,
+	0x2c8d,
+	0x2c8f,
+	0x2c91,
+	0x2c93,
+	0x2c95,
+	0x2c97,
+	0x2c99,
+	0x2c9b,
+	0x2c9d,
+	0x2c9f,
+	0x2ca1,
+	0x2ca3,
+	0x2ca5,
+	0x2ca7,
+	0x2ca9,
+	0x2cab,
+	0x2cad,
+	0x2caf,
+	0x2cb1,
+	0x2cb3,
+	0x2cb5,
+	0x2cb7,
+	0x2cb9,
+	0x2cbb,
+	0x2cbd,
+	0x2cbf,
+	0x2cc1,
+	0x2cc3,
+	0x2cc5,
+	0x2cc7,
+	0x2cc9,
+	0x2ccb,
+	0x2ccd,
+	0x2ccf,
+	0x2cd1,
+	0x2cd3,
+	0x2cd5,
+	0x2cd7,
+	0x2cd9,
+	0x2cdb,
+	0x2cdd,
+	0x2cdf,
+	0x2ce1,
+	0x2cec,
+	0x2cee,
+	0x2cf3,
+	0x2d27,
+	0x2d2d,
+	0xa641,
+	0xa643,
+	0xa645,
+	0xa647,
+	0xa649,
+	0xa64b,
+	0xa64d,
+	0xa64f,
+	0xa651,
+	0xa653,
+	0xa655,
+	0xa657,
+	0xa659,
+	0xa65b,
+	0xa65d,
+	0xa65f,
+	0xa661,
+	0xa663,
+	0xa665,
+	0xa667,
+	0xa669,
+	0xa66b,
+	0xa66d,
+	0xa681,
+	0xa683,
+	0xa685,
+	0xa687,
+	0xa689,
+	0xa68b,
+	0xa68d,
+	0xa68f,
+	0xa691,
+	0xa693,
+	0xa695,
+	0xa697,
+	0xa723,
+	0xa725,
+	0xa727,
+	0xa729,
+	0xa72b,
+	0xa72d,
+	0xa733,
+	0xa735,
+	0xa737,
+	0xa739,
+	0xa73b,
+	0xa73d,
+	0xa73f,
+	0xa741,
+	0xa743,
+	0xa745,
+	0xa747,
+	0xa749,
+	0xa74b,
+	0xa74d,
+	0xa74f,
+	0xa751,
+	0xa753,
+	0xa755,
+	0xa757,
+	0xa759,
+	0xa75b,
+	0xa75d,
+	0xa75f,
+	0xa761,
+	0xa763,
+	0xa765,
+	0xa767,
+	0xa769,
+	0xa76b,
+	0xa76d,
+	0xa76f,
+	0xa77a,
+	0xa77c,
+	0xa77f,
+	0xa781,
+	0xa783,
+	0xa785,
+	0xa787,
+	0xa78c,
+	0xa78e,
+	0xa791,
+	0xa793,
+	0xa7a1,
+	0xa7a3,
+	0xa7a5,
+	0xa7a7,
+	0xa7a9,
+	0xa7fa,
+	0x1d4bb,
+	0x1d7cb,
+};
+
+/* }}} */
+
+/* {{{ Unicode title */
+
+static uint32_t istitler[] = {
+	0x0041, 0x005a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00de,
+	0x0178, 0x0179,
+	0x0181, 0x0182,
+	0x0186, 0x0187,
+	0x0189, 0x018b,
+	0x018e, 0x0191,
+	0x0193, 0x0194,
+	0x0196, 0x0198,
+	0x019c, 0x019d,
+	0x019f, 0x01a0,
+	0x01a6, 0x01a7,
+	0x01ae, 0x01af,
+	0x01b1, 0x01b3,
+	0x01b7, 0x01b8,
+	0x01f6, 0x01f8,
+	0x023a, 0x023b,
+	0x023d, 0x023e,
+	0x0243, 0x0246,
+	0x0388, 0x038a,
+	0x038e, 0x038f,
+	0x0391, 0x03a1,
+	0x03a3, 0x03ab,
+	0x03f9, 0x03fa,
+	0x03fd, 0x042f,
+	0x04c0, 0x04c1,
+	0x0531, 0x0556,
+	0x10a0, 0x10c5,
+	0x1f08, 0x1f0f,
+	0x1f18, 0x1f1d,
+	0x1f28, 0x1f2f,
+	0x1f38, 0x1f3f,
+	0x1f48, 0x1f4d,
+	0x1f68, 0x1f6f,
+	0x1f88, 0x1f8f,
+	0x1f98, 0x1f9f,
+	0x1fa8, 0x1faf,
+	0x1fb8, 0x1fbc,
+	0x1fc8, 0x1fcc,
+	0x1fd8, 0x1fdb,
+	0x1fe8, 0x1fec,
+	0x1ff8, 0x1ffc,
+	0x2160, 0x216f,
+	0x24b6, 0x24cf,
+	0x2c00, 0x2c2e,
+	0x2c62, 0x2c64,
+	0x2c6d, 0x2c70,
+	0x2c7e, 0x2c80,
+	0xa77d, 0xa77e,
+	0xff21, 0xff3a,
+	0x10400, 0x10427,
+};
+
+/* }}} */
+
+/* {{{ Title */
+
+static uint32_t istitles[] = {
+	0x0100,
+	0x0102,
+	0x0104,
+	0x0106,
+	0x0108,
+	0x010a,
+	0x010c,
+	0x010e,
+	0x0110,
+	0x0112,
+	0x0114,
+	0x0116,
+	0x0118,
+	0x011a,
+	0x011c,
+	0x011e,
+	0x0120,
+	0x0122,
+	0x0124,
+	0x0126,
+	0x0128,
+	0x012a,
+	0x012c,
+	0x012e,
+	0x0132,
+	0x0134,
+	0x0136,
+	0x0139,
+	0x013b,
+	0x013d,
+	0x013f,
+	0x0141,
+	0x0143,
+	0x0145,
+	0x0147,
+	0x014a,
+	0x014c,
+	0x014e,
+	0x0150,
+	0x0152,
+	0x0154,
+	0x0156,
+	0x0158,
+	0x015a,
+	0x015c,
+	0x015e,
+	0x0160,
+	0x0162,
+	0x0164,
+	0x0166,
+	0x0168,
+	0x016a,
+	0x016c,
+	0x016e,
+	0x0170,
+	0x0172,
+	0x0174,
+	0x0176,
+	0x017b,
+	0x017d,
+	0x0184,
+	0x01a2,
+	0x01a4,
+	0x01a9,
+	0x01ac,
+	0x01b5,
+	0x01bc,
+	0x01c5,
+	0x01c8,
+	0x01cb,
+	0x01cd,
+	0x01cf,
+	0x01d1,
+	0x01d3,
+	0x01d5,
+	0x01d7,
+	0x01d9,
+	0x01db,
+	0x01de,
+	0x01e0,
+	0x01e2,
+	0x01e4,
+	0x01e6,
+	0x01e8,
+	0x01ea,
+	0x01ec,
+	0x01ee,
+	0x01f2,
+	0x01f4,
+	0x01fa,
+	0x01fc,
+	0x01fe,
+	0x0200,
+	0x0202,
+	0x0204,
+	0x0206,
+	0x0208,
+	0x020a,
+	0x020c,
+	0x020e,
+	0x0210,
+	0x0212,
+	0x0214,
+	0x0216,
+	0x0218,
+	0x021a,
+	0x021c,
+	0x021e,
+	0x0220,
+	0x0222,
+	0x0224,
+	0x0226,
+	0x0228,
+	0x022a,
+	0x022c,
+	0x022e,
+	0x0230,
+	0x0232,
+	0x0241,
+	0x0248,
+	0x024a,
+	0x024c,
+	0x024e,
+	0x0370,
+	0x0372,
+	0x0376,
+	0x0386,
+	0x038c,
+	0x03cf,
+	0x03d8,
+	0x03da,
+	0x03dc,
+	0x03de,
+	0x03e0,
+	0x03e2,
+	0x03e4,
+	0x03e6,
+	0x03e8,
+	0x03ea,
+	0x03ec,
+	0x03ee,
+	0x03f7,
+	0x0460,
+	0x0462,
+	0x0464,
+	0x0466,
+	0x0468,
+	0x046a,
+	0x046c,
+	0x046e,
+	0x0470,
+	0x0472,
+	0x0474,
+	0x0476,
+	0x0478,
+	0x047a,
+	0x047c,
+	0x047e,
+	0x0480,
+	0x048a,
+	0x048c,
+	0x048e,
+	0x0490,
+	0x0492,
+	0x0494,
+	0x0496,
+	0x0498,
+	0x049a,
+	0x049c,
+	0x049e,
+	0x04a0,
+	0x04a2,
+	0x04a4,
+	0x04a6,
+	0x04a8,
+	0x04aa,
+	0x04ac,
+	0x04ae,
+	0x04b0,
+	0x04b2,
+	0x04b4,
+	0x04b6,
+	0x04b8,
+	0x04ba,
+	0x04bc,
+	0x04be,
+	0x04c3,
+	0x04c5,
+	0x04c7,
+	0x04c9,
+	0x04cb,
+	0x04cd,
+	0x04d0,
+	0x04d2,
+	0x04d4,
+	0x04d6,
+	0x04d8,
+	0x04da,
+	0x04dc,
+	0x04de,
+	0x04e0,
+	0x04e2,
+	0x04e4,
+	0x04e6,
+	0x04e8,
+	0x04ea,
+	0x04ec,
+	0x04ee,
+	0x04f0,
+	0x04f2,
+	0x04f4,
+	0x04f6,
+	0x04f8,
+	0x04fa,
+	0x04fc,
+	0x04fe,
+	0x0500,
+	0x0502,
+	0x0504,
+	0x0506,
+	0x0508,
+	0x050a,
+	0x050c,
+	0x050e,
+	0x0510,
+	0x0512,
+	0x0514,
+	0x0516,
+	0x0518,
+	0x051a,
+	0x051c,
+	0x051e,
+	0x0520,
+	0x0522,
+	0x0524,
+	0x0526,
+	0x10c7,
+	0x10cd,
+	0x1e00,
+	0x1e02,
+	0x1e04,
+	0x1e06,
+	0x1e08,
+	0x1e0a,
+	0x1e0c,
+	0x1e0e,
+	0x1e10,
+	0x1e12,
+	0x1e14,
+	0x1e16,
+	0x1e18,
+	0x1e1a,
+	0x1e1c,
+	0x1e1e,
+	0x1e20,
+	0x1e22,
+	0x1e24,
+	0x1e26,
+	0x1e28,
+	0x1e2a,
+	0x1e2c,
+	0x1e2e,
+	0x1e30,
+	0x1e32,
+	0x1e34,
+	0x1e36,
+	0x1e38,
+	0x1e3a,
+	0x1e3c,
+	0x1e3e,
+	0x1e40,
+	0x1e42,
+	0x1e44,
+	0x1e46,
+	0x1e48,
+	0x1e4a,
+	0x1e4c,
+	0x1e4e,
+	0x1e50,
+	0x1e52,
+	0x1e54,
+	0x1e56,
+	0x1e58,
+	0x1e5a,
+	0x1e5c,
+	0x1e5e,
+	0x1e60,
+	0x1e62,
+	0x1e64,
+	0x1e66,
+	0x1e68,
+	0x1e6a,
+	0x1e6c,
+	0x1e6e,
+	0x1e70,
+	0x1e72,
+	0x1e74,
+	0x1e76,
+	0x1e78,
+	0x1e7a,
+	0x1e7c,
+	0x1e7e,
+	0x1e80,
+	0x1e82,
+	0x1e84,
+	0x1e86,
+	0x1e88,
+	0x1e8a,
+	0x1e8c,
+	0x1e8e,
+	0x1e90,
+	0x1e92,
+	0x1e94,
+	0x1ea0,
+	0x1ea2,
+	0x1ea4,
+	0x1ea6,
+	0x1ea8,
+	0x1eaa,
+	0x1eac,
+	0x1eae,
+	0x1eb0,
+	0x1eb2,
+	0x1eb4,
+	0x1eb6,
+	0x1eb8,
+	0x1eba,
+	0x1ebc,
+	0x1ebe,
+	0x1ec0,
+	0x1ec2,
+	0x1ec4,
+	0x1ec6,
+	0x1ec8,
+	0x1eca,
+	0x1ecc,
+	0x1ece,
+	0x1ed0,
+	0x1ed2,
+	0x1ed4,
+	0x1ed6,
+	0x1ed8,
+	0x1eda,
+	0x1edc,
+	0x1ede,
+	0x1ee0,
+	0x1ee2,
+	0x1ee4,
+	0x1ee6,
+	0x1ee8,
+	0x1eea,
+	0x1eec,
+	0x1eee,
+	0x1ef0,
+	0x1ef2,
+	0x1ef4,
+	0x1ef6,
+	0x1ef8,
+	0x1efa,
+	0x1efc,
+	0x1efe,
+	0x1f59,
+	0x1f5b,
+	0x1f5d,
+	0x1f5f,
+	0x2132,
+	0x2183,
+	0x2c60,
+	0x2c67,
+	0x2c69,
+	0x2c6b,
+	0x2c72,
+	0x2c75,
+	0x2c82,
+	0x2c84,
+	0x2c86,
+	0x2c88,
+	0x2c8a,
+	0x2c8c,
+	0x2c8e,
+	0x2c90,
+	0x2c92,
+	0x2c94,
+	0x2c96,
+	0x2c98,
+	0x2c9a,
+	0x2c9c,
+	0x2c9e,
+	0x2ca0,
+	0x2ca2,
+	0x2ca4,
+	0x2ca6,
+	0x2ca8,
+	0x2caa,
+	0x2cac,
+	0x2cae,
+	0x2cb0,
+	0x2cb2,
+	0x2cb4,
+	0x2cb6,
+	0x2cb8,
+	0x2cba,
+	0x2cbc,
+	0x2cbe,
+	0x2cc0,
+	0x2cc2,
+	0x2cc4,
+	0x2cc6,
+	0x2cc8,
+	0x2cca,
+	0x2ccc,
+	0x2cce,
+	0x2cd0,
+	0x2cd2,
+	0x2cd4,
+	0x2cd6,
+	0x2cd8,
+	0x2cda,
+	0x2cdc,
+	0x2cde,
+	0x2ce0,
+	0x2ce2,
+	0x2ceb,
+	0x2ced,
+	0x2cf2,
+	0xa640,
+	0xa642,
+	0xa644,
+	0xa646,
+	0xa648,
+	0xa64a,
+	0xa64c,
+	0xa64e,
+	0xa650,
+	0xa652,
+	0xa654,
+	0xa656,
+	0xa658,
+	0xa65a,
+	0xa65c,
+	0xa65e,
+	0xa660,
+	0xa662,
+	0xa664,
+	0xa666,
+	0xa668,
+	0xa66a,
+	0xa66c,
+	0xa680,
+	0xa682,
+	0xa684,
+	0xa686,
+	0xa688,
+	0xa68a,
+	0xa68c,
+	0xa68e,
+	0xa690,
+	0xa692,
+	0xa694,
+	0xa696,
+	0xa722,
+	0xa724,
+	0xa726,
+	0xa728,
+	0xa72a,
+	0xa72c,
+	0xa72e,
+	0xa732,
+	0xa734,
+	0xa736,
+	0xa738,
+	0xa73a,
+	0xa73c,
+	0xa73e,
+	0xa740,
+	0xa742,
+	0xa744,
+	0xa746,
+	0xa748,
+	0xa74a,
+	0xa74c,
+	0xa74e,
+	0xa750,
+	0xa752,
+	0xa754,
+	0xa756,
+	0xa758,
+	0xa75a,
+	0xa75c,
+	0xa75e,
+	0xa760,
+	0xa762,
+	0xa764,
+	0xa766,
+	0xa768,
+	0xa76a,
+	0xa76c,
+	0xa76e,
+	0xa779,
+	0xa77b,
+	0xa780,
+	0xa782,
+	0xa784,
+	0xa786,
+	0xa78b,
+	0xa78d,
+	0xa790,
+	0xa792,
+	0xa7a0,
+	0xa7a2,
+	0xa7a4,
+	0xa7a6,
+	0xa7a8,
+	0xa7aa,
+};
+
+/* }}} */
+
+/* {{{ To upper */
+
+static uint32_t toupperr[] = {
+	0x0061, 0x007a, 1048544,
+	0x00e0, 0x00f6, 1048544,
+	0x00f8, 0x00fe, 1048544,
+	0x023f, 0x0240, 1059391,
+	0x0256, 0x0257, 1048371,
+	0x028a, 0x028b, 1048359,
+	0x037b, 0x037d, 1048706,
+	0x03ad, 0x03af, 1048539,
+	0x03b1, 0x03c1, 1048544,
+	0x03c3, 0x03cb, 1048544,
+	0x03cd, 0x03ce, 1048513,
+	0x0430, 0x044f, 1048544,
+	0x0450, 0x045f, 1048496,
+	0x0561, 0x0586, 1048528,
+	0x1f00, 0x1f07, 1048584,
+	0x1f10, 0x1f15, 1048584,
+	0x1f20, 0x1f27, 1048584,
+	0x1f30, 0x1f37, 1048584,
+	0x1f40, 0x1f45, 1048584,
+	0x1f60, 0x1f67, 1048584,
+	0x1f70, 0x1f71, 1048650,
+	0x1f72, 0x1f75, 1048662,
+	0x1f76, 0x1f77, 1048676,
+	0x1f78, 0x1f79, 1048704,
+	0x1f7a, 0x1f7b, 1048688,
+	0x1f7c, 0x1f7d, 1048702,
+	0x1f80, 0x1f87, 1048584,
+	0x1f90, 0x1f97, 1048584,
+	0x1fa0, 0x1fa7, 1048584,
+	0x1fb0, 0x1fb1, 1048584,
+	0x1fd0, 0x1fd1, 1048584,
+	0x1fe0, 0x1fe1, 1048584,
+	0x2170, 0x217f, 1048560,
+	0x24d0, 0x24e9, 1048550,
+	0x2c30, 0x2c5e, 1048528,
+	0x2d00, 0x2d25, 1041312,
+	0xff41, 0xff5a, 1048544,
+	0x10428, 0x1044f, 1048536,
+};
+
+static uint32_t touppers[] = {
+	0x00b5, 1049319,
+	0x00ff, 1048697,
+	0x0101, 1048575,
+	0x0103, 1048575,
+	0x0105, 1048575,
+	0x0107, 1048575,
+	0x0109, 1048575,
+	0x010b, 1048575,
+	0x010d, 1048575,
+	0x010f, 1048575,
+	0x0111, 1048575,
+	0x0113, 1048575,
+	0x0115, 1048575,
+	0x0117, 1048575,
+	0x0119, 1048575,
+	0x011b, 1048575,
+	0x011d, 1048575,
+	0x011f, 1048575,
+	0x0121, 1048575,
+	0x0123, 1048575,
+	0x0125, 1048575,
+	0x0127, 1048575,
+	0x0129, 1048575,
+	0x012b, 1048575,
+	0x012d, 1048575,
+	0x012f, 1048575,
+	0x0131, 1048344,
+	0x0133, 1048575,
+	0x0135, 1048575,
+	0x0137, 1048575,
+	0x013a, 1048575,
+	0x013c, 1048575,
+	0x013e, 1048575,
+	0x0140, 1048575,
+	0x0142, 1048575,
+	0x0144, 1048575,
+	0x0146, 1048575,
+	0x0148, 1048575,
+	0x014b, 1048575,
+	0x014d, 1048575,
+	0x014f, 1048575,
+	0x0151, 1048575,
+	0x0153, 1048575,
+	0x0155, 1048575,
+	0x0157, 1048575,
+	0x0159, 1048575,
+	0x015b, 1048575,
+	0x015d, 1048575,
+	0x015f, 1048575,
+	0x0161, 1048575,
+	0x0163, 1048575,
+	0x0165, 1048575,
+	0x0167, 1048575,
+	0x0169, 1048575,
+	0x016b, 1048575,
+	0x016d, 1048575,
+	0x016f, 1048575,
+	0x0171, 1048575,
+	0x0173, 1048575,
+	0x0175, 1048575,
+	0x0177, 1048575,
+	0x017a, 1048575,
+	0x017c, 1048575,
+	0x017e, 1048575,
+	0x017f, 1048276,
+	0x0180, 1048771,
+	0x0183, 1048575,
+	0x0185, 1048575,
+	0x0188, 1048575,
+	0x018c, 1048575,
+	0x0192, 1048575,
+	0x0195, 1048673,
+	0x0199, 1048575,
+	0x019a, 1048739,
+	0x019e, 1048706,
+	0x01a1, 1048575,
+	0x01a3, 1048575,
+	0x01a5, 1048575,
+	0x01a8, 1048575,
+	0x01ad, 1048575,
+	0x01b0, 1048575,
+	0x01b4, 1048575,
+	0x01b6, 1048575,
+	0x01b9, 1048575,
+	0x01bd, 1048575,
+	0x01bf, 1048632,
+	0x01c5, 1048575,
+	0x01c6, 1048574,
+	0x01c8, 1048575,
+	0x01c9, 1048574,
+	0x01cb, 1048575,
+	0x01cc, 1048574,
+	0x01ce, 1048575,
+	0x01d0, 1048575,
+	0x01d2, 1048575,
+	0x01d4, 1048575,
+	0x01d6, 1048575,
+	0x01d8, 1048575,
+	0x01da, 1048575,
+	0x01dc, 1048575,
+	0x01dd, 1048497,
+	0x01df, 1048575,
+	0x01e1, 1048575,
+	0x01e3, 1048575,
+	0x01e5, 1048575,
+	0x01e7, 1048575,
+	0x01e9, 1048575,
+	0x01eb, 1048575,
+	0x01ed, 1048575,
+	0x01ef, 1048575,
+	0x01f2, 1048575,
+	0x01f3, 1048574,
+	0x01f5, 1048575,
+	0x01f9, 1048575,
+	0x01fb, 1048575,
+	0x01fd, 1048575,
+	0x01ff, 1048575,
+	0x0201, 1048575,
+	0x0203, 1048575,
+	0x0205, 1048575,
+	0x0207, 1048575,
+	0x0209, 1048575,
+	0x020b, 1048575,
+	0x020d, 1048575,
+	0x020f, 1048575,
+	0x0211, 1048575,
+	0x0213, 1048575,
+	0x0215, 1048575,
+	0x0217, 1048575,
+	0x0219, 1048575,
+	0x021b, 1048575,
+	0x021d, 1048575,
+	0x021f, 1048575,
+	0x0223, 1048575,
+	0x0225, 1048575,
+	0x0227, 1048575,
+	0x0229, 1048575,
+	0x022b, 1048575,
+	0x022d, 1048575,
+	0x022f, 1048575,
+	0x0231, 1048575,
+	0x0233, 1048575,
+	0x023c, 1048575,
+	0x0242, 1048575,
+	0x0247, 1048575,
+	0x0249, 1048575,
+	0x024b, 1048575,
+	0x024d, 1048575,
+	0x024f, 1048575,
+	0x0250, 1059359,
+	0x0251, 1059356,
+	0x0252, 1059358,
+	0x0253, 1048366,
+	0x0254, 1048370,
+	0x0259, 1048374,
+	0x025b, 1048373,
+	0x0260, 1048371,
+	0x0263, 1048369,
+	0x0265, 1090856,
+	0x0266, 1090884,
+	0x0268, 1048367,
+	0x0269, 1048365,
+	0x026b, 1059319,
+	0x026f, 1048365,
+	0x0271, 1059325,
+	0x0272, 1048363,
+	0x0275, 1048362,
+	0x027d, 1059303,
+	0x0280, 1048358,
+	0x0283, 1048358,
+	0x0288, 1048358,
+	0x0289, 1048507,
+	0x028c, 1048505,
+	0x0292, 1048357,
+	0x0345, 1048660,
+	0x0371, 1048575,
+	0x0373, 1048575,
+	0x0377, 1048575,
+	0x03ac, 1048538,
+	0x03c2, 1048545,
+	0x03cc, 1048512,
+	0x03d0, 1048514,
+	0x03d1, 1048519,
+	0x03d5, 1048529,
+	0x03d6, 1048522,
+	0x03d7, 1048568,
+	0x03d9, 1048575,
+	0x03db, 1048575,
+	0x03dd, 1048575,
+	0x03df, 1048575,
+	0x03e1, 1048575,
+	0x03e3, 1048575,
+	0x03e5, 1048575,
+	0x03e7, 1048575,
+	0x03e9, 1048575,
+	0x03eb, 1048575,
+	0x03ed, 1048575,
+	0x03ef, 1048575,
+	0x03f0, 1048490,
+	0x03f1, 1048496,
+	0x03f2, 1048583,
+	0x03f5, 1048480,
+	0x03f8, 1048575,
+	0x03fb, 1048575,
+	0x0461, 1048575,
+	0x0463, 1048575,
+	0x0465, 1048575,
+	0x0467, 1048575,
+	0x0469, 1048575,
+	0x046b, 1048575,
+	0x046d, 1048575,
+	0x046f, 1048575,
+	0x0471, 1048575,
+	0x0473, 1048575,
+	0x0475, 1048575,
+	0x0477, 1048575,
+	0x0479, 1048575,
+	0x047b, 1048575,
+	0x047d, 1048575,
+	0x047f, 1048575,
+	0x0481, 1048575,
+	0x048b, 1048575,
+	0x048d, 1048575,
+	0x048f, 1048575,
+	0x0491, 1048575,
+	0x0493, 1048575,
+	0x0495, 1048575,
+	0x0497, 1048575,
+	0x0499, 1048575,
+	0x049b, 1048575,
+	0x049d, 1048575,
+	0x049f, 1048575,
+	0x04a1, 1048575,
+	0x04a3, 1048575,
+	0x04a5, 1048575,
+	0x04a7, 1048575,
+	0x04a9, 1048575,
+	0x04ab, 1048575,
+	0x04ad, 1048575,
+	0x04af, 1048575,
+	0x04b1, 1048575,
+	0x04b3, 1048575,
+	0x04b5, 1048575,
+	0x04b7, 1048575,
+	0x04b9, 1048575,
+	0x04bb, 1048575,
+	0x04bd, 1048575,
+	0x04bf, 1048575,
+	0x04c2, 1048575,
+	0x04c4, 1048575,
+	0x04c6, 1048575,
+	0x04c8, 1048575,
+	0x04ca, 1048575,
+	0x04cc, 1048575,
+	0x04ce, 1048575,
+	0x04cf, 1048561,
+	0x04d1, 1048575,
+	0x04d3, 1048575,
+	0x04d5, 1048575,
+	0x04d7, 1048575,
+	0x04d9, 1048575,
+	0x04db, 1048575,
+	0x04dd, 1048575,
+	0x04df, 1048575,
+	0x04e1, 1048575,
+	0x04e3, 1048575,
+	0x04e5, 1048575,
+	0x04e7, 1048575,
+	0x04e9, 1048575,
+	0x04eb, 1048575,
+	0x04ed, 1048575,
+	0x04ef, 1048575,
+	0x04f1, 1048575,
+	0x04f3, 1048575,
+	0x04f5, 1048575,
+	0x04f7, 1048575,
+	0x04f9, 1048575,
+	0x04fb, 1048575,
+	0x04fd, 1048575,
+	0x04ff, 1048575,
+	0x0501, 1048575,
+	0x0503, 1048575,
+	0x0505, 1048575,
+	0x0507, 1048575,
+	0x0509, 1048575,
+	0x050b, 1048575,
+	0x050d, 1048575,
+	0x050f, 1048575,
+	0x0511, 1048575,
+	0x0513, 1048575,
+	0x0515, 1048575,
+	0x0517, 1048575,
+	0x0519, 1048575,
+	0x051b, 1048575,
+	0x051d, 1048575,
+	0x051f, 1048575,
+	0x0521, 1048575,
+	0x0523, 1048575,
+	0x0525, 1048575,
+	0x0527, 1048575,
+	0x1d79, 1083908,
+	0x1d7d, 1052390,
+	0x1e01, 1048575,
+	0x1e03, 1048575,
+	0x1e05, 1048575,
+	0x1e07, 1048575,
+	0x1e09, 1048575,
+	0x1e0b, 1048575,
+	0x1e0d, 1048575,
+	0x1e0f, 1048575,
+	0x1e11, 1048575,
+	0x1e13, 1048575,
+	0x1e15, 1048575,
+	0x1e17, 1048575,
+	0x1e19, 1048575,
+	0x1e1b, 1048575,
+	0x1e1d, 1048575,
+	0x1e1f, 1048575,
+	0x1e21, 1048575,
+	0x1e23, 1048575,
+	0x1e25, 1048575,
+	0x1e27, 1048575,
+	0x1e29, 1048575,
+	0x1e2b, 1048575,
+	0x1e2d, 1048575,
+	0x1e2f, 1048575,
+	0x1e31, 1048575,
+	0x1e33, 1048575,
+	0x1e35, 1048575,
+	0x1e37, 1048575,
+	0x1e39, 1048575,
+	0x1e3b, 1048575,
+	0x1e3d, 1048575,
+	0x1e3f, 1048575,
+	0x1e41, 1048575,
+	0x1e43, 1048575,
+	0x1e45, 1048575,
+	0x1e47, 1048575,
+	0x1e49, 1048575,
+	0x1e4b, 1048575,
+	0x1e4d, 1048575,
+	0x1e4f, 1048575,
+	0x1e51, 1048575,
+	0x1e53, 1048575,
+	0x1e55, 1048575,
+	0x1e57, 1048575,
+	0x1e59, 1048575,
+	0x1e5b, 1048575,
+	0x1e5d, 1048575,
+	0x1e5f, 1048575,
+	0x1e61, 1048575,
+	0x1e63, 1048575,
+	0x1e65, 1048575,
+	0x1e67, 1048575,
+	0x1e69, 1048575,
+	0x1e6b, 1048575,
+	0x1e6d, 1048575,
+	0x1e6f, 1048575,
+	0x1e71, 1048575,
+	0x1e73, 1048575,
+	0x1e75, 1048575,
+	0x1e77, 1048575,
+	0x1e79, 1048575,
+	0x1e7b, 1048575,
+	0x1e7d, 1048575,
+	0x1e7f, 1048575,
+	0x1e81, 1048575,
+	0x1e83, 1048575,
+	0x1e85, 1048575,
+	0x1e87, 1048575,
+	0x1e89, 1048575,
+	0x1e8b, 1048575,
+	0x1e8d, 1048575,
+	0x1e8f, 1048575,
+	0x1e91, 1048575,
+	0x1e93, 1048575,
+	0x1e95, 1048575,
+	0x1e9b, 1048517,
+	0x1ea1, 1048575,
+	0x1ea3, 1048575,
+	0x1ea5, 1048575,
+	0x1ea7, 1048575,
+	0x1ea9, 1048575,
+	0x1eab, 1048575,
+	0x1ead, 1048575,
+	0x1eaf, 1048575,
+	0x1eb1, 1048575,
+	0x1eb3, 1048575,
+	0x1eb5, 1048575,
+	0x1eb7, 1048575,
+	0x1eb9, 1048575,
+	0x1ebb, 1048575,
+	0x1ebd, 1048575,
+	0x1ebf, 1048575,
+	0x1ec1, 1048575,
+	0x1ec3, 1048575,
+	0x1ec5, 1048575,
+	0x1ec7, 1048575,
+	0x1ec9, 1048575,
+	0x1ecb, 1048575,
+	0x1ecd, 1048575,
+	0x1ecf, 1048575,
+	0x1ed1, 1048575,
+	0x1ed3, 1048575,
+	0x1ed5, 1048575,
+	0x1ed7, 1048575,
+	0x1ed9, 1048575,
+	0x1edb, 1048575,
+	0x1edd, 1048575,
+	0x1edf, 1048575,
+	0x1ee1, 1048575,
+	0x1ee3, 1048575,
+	0x1ee5, 1048575,
+	0x1ee7, 1048575,
+	0x1ee9, 1048575,
+	0x1eeb, 1048575,
+	0x1eed, 1048575,
+	0x1eef, 1048575,
+	0x1ef1, 1048575,
+	0x1ef3, 1048575,
+	0x1ef5, 1048575,
+	0x1ef7, 1048575,
+	0x1ef9, 1048575,
+	0x1efb, 1048575,
+	0x1efd, 1048575,
+	0x1eff, 1048575,
+	0x1f51, 1048584,
+	0x1f53, 1048584,
+	0x1f55, 1048584,
+	0x1f57, 1048584,
+	0x1fb3, 1048585,
+	0x1fbe, 1041371,
+	0x1fc3, 1048585,
+	0x1fe5, 1048583,
+	0x1ff3, 1048585,
+	0x214e, 1048548,
+	0x2184, 1048575,
+	0x2c61, 1048575,
+	0x2c65, 1037781,
+	0x2c66, 1037784,
+	0x2c68, 1048575,
+	0x2c6a, 1048575,
+	0x2c6c, 1048575,
+	0x2c73, 1048575,
+	0x2c76, 1048575,
+	0x2c81, 1048575,
+	0x2c83, 1048575,
+	0x2c85, 1048575,
+	0x2c87, 1048575,
+	0x2c89, 1048575,
+	0x2c8b, 1048575,
+	0x2c8d, 1048575,
+	0x2c8f, 1048575,
+	0x2c91, 1048575,
+	0x2c93, 1048575,
+	0x2c95, 1048575,
+	0x2c97, 1048575,
+	0x2c99, 1048575,
+	0x2c9b, 1048575,
+	0x2c9d, 1048575,
+	0x2c9f, 1048575,
+	0x2ca1, 1048575,
+	0x2ca3, 1048575,
+	0x2ca5, 1048575,
+	0x2ca7, 1048575,
+	0x2ca9, 1048575,
+	0x2cab, 1048575,
+	0x2cad, 1048575,
+	0x2caf, 1048575,
+	0x2cb1, 1048575,
+	0x2cb3, 1048575,
+	0x2cb5, 1048575,
+	0x2cb7, 1048575,
+	0x2cb9, 1048575,
+	0x2cbb, 1048575,
+	0x2cbd, 1048575,
+	0x2cbf, 1048575,
+	0x2cc1, 1048575,
+	0x2cc3, 1048575,
+	0x2cc5, 1048575,
+	0x2cc7, 1048575,
+	0x2cc9, 1048575,
+	0x2ccb, 1048575,
+	0x2ccd, 1048575,
+	0x2ccf, 1048575,
+	0x2cd1, 1048575,
+	0x2cd3, 1048575,
+	0x2cd5, 1048575,
+	0x2cd7, 1048575,
+	0x2cd9, 1048575,
+	0x2cdb, 1048575,
+	0x2cdd, 1048575,
+	0x2cdf, 1048575,
+	0x2ce1, 1048575,
+	0x2ce3, 1048575,
+	0x2cec, 1048575,
+	0x2cee, 1048575,
+	0x2cf3, 1048575,
+	0x2d27, 1041312,
+	0x2d2d, 1041312,
+	0xa641, 1048575,
+	0xa643, 1048575,
+	0xa645, 1048575,
+	0xa647, 1048575,
+	0xa649, 1048575,
+	0xa64b, 1048575,
+	0xa64d, 1048575,
+	0xa64f, 1048575,
+	0xa651, 1048575,
+	0xa653, 1048575,
+	0xa655, 1048575,
+	0xa657, 1048575,
+	0xa659, 1048575,
+	0xa65b, 1048575,
+	0xa65d, 1048575,
+	0xa65f, 1048575,
+	0xa661, 1048575,
+	0xa663, 1048575,
+	0xa665, 1048575,
+	0xa667, 1048575,
+	0xa669, 1048575,
+	0xa66b, 1048575,
+	0xa66d, 1048575,
+	0xa681, 1048575,
+	0xa683, 1048575,
+	0xa685, 1048575,
+	0xa687, 1048575,
+	0xa689, 1048575,
+	0xa68b, 1048575,
+	0xa68d, 1048575,
+	0xa68f, 1048575,
+	0xa691, 1048575,
+	0xa693, 1048575,
+	0xa695, 1048575,
+	0xa697, 1048575,
+	0xa723, 1048575,
+	0xa725, 1048575,
+	0xa727, 1048575,
+	0xa729, 1048575,
+	0xa72b, 1048575,
+	0xa72d, 1048575,
+	0xa72f, 1048575,
+	0xa733, 1048575,
+	0xa735, 1048575,
+	0xa737, 1048575,
+	0xa739, 1048575,
+	0xa73b, 1048575,
+	0xa73d, 1048575,
+	0xa73f, 1048575,
+	0xa741, 1048575,
+	0xa743, 1048575,
+	0xa745, 1048575,
+	0xa747, 1048575,
+	0xa749, 1048575,
+	0xa74b, 1048575,
+	0xa74d, 1048575,
+	0xa74f, 1048575,
+	0xa751, 1048575,
+	0xa753, 1048575,
+	0xa755, 1048575,
+	0xa757, 1048575,
+	0xa759, 1048575,
+	0xa75b, 1048575,
+	0xa75d, 1048575,
+	0xa75f, 1048575,
+	0xa761, 1048575,
+	0xa763, 1048575,
+	0xa765, 1048575,
+	0xa767, 1048575,
+	0xa769, 1048575,
+	0xa76b, 1048575,
+	0xa76d, 1048575,
+	0xa76f, 1048575,
+	0xa77a, 1048575,
+	0xa77c, 1048575,
+	0xa77f, 1048575,
+	0xa781, 1048575,
+	0xa783, 1048575,
+	0xa785, 1048575,
+	0xa787, 1048575,
+	0xa78c, 1048575,
+	0xa791, 1048575,
+	0xa793, 1048575,
+	0xa7a1, 1048575,
+	0xa7a3, 1048575,
+	0xa7a5, 1048575,
+	0xa7a7, 1048575,
+	0xa7a9, 1048575,
+};
+
+/* }}} */
+
+/* {{{ To lower */
+
+static uint32_t tolowerr[] = {
+	0x0041, 0x005a, 1048608,
+	0x00c0, 0x00d6, 1048608,
+	0x00d8, 0x00de, 1048608,
+	0x0189, 0x018a, 1048781,
+	0x01b1, 0x01b2, 1048793,
+	0x0388, 0x038a, 1048613,
+	0x038e, 0x038f, 1048639,
+	0x0391, 0x03a1, 1048608,
+	0x03a3, 0x03ab, 1048608,
+	0x03fd, 0x03ff, 1048446,
+	0x0400, 0x040f, 1048656,
+	0x0410, 0x042f, 1048608,
+	0x0531, 0x0556, 1048624,
+	0x10a0, 0x10c5, 1055840,
+	0x1f08, 0x1f0f, 1048568,
+	0x1f18, 0x1f1d, 1048568,
+	0x1f28, 0x1f2f, 1048568,
+	0x1f38, 0x1f3f, 1048568,
+	0x1f48, 0x1f4d, 1048568,
+	0x1f68, 0x1f6f, 1048568,
+	0x1f88, 0x1f8f, 1048568,
+	0x1f98, 0x1f9f, 1048568,
+	0x1fa8, 0x1faf, 1048568,
+	0x1fb8, 0x1fb9, 1048568,
+	0x1fba, 0x1fbb, 1048502,
+	0x1fc8, 0x1fcb, 1048490,
+	0x1fd8, 0x1fd9, 1048568,
+	0x1fda, 0x1fdb, 1048476,
+	0x1fe8, 0x1fe9, 1048568,
+	0x1fea, 0x1feb, 1048464,
+	0x1ff8, 0x1ff9, 1048448,
+	0x1ffa, 0x1ffb, 1048450,
+	0x2160, 0x216f, 1048592,
+	0x24b6, 0x24cf, 1048602,
+	0x2c00, 0x2c2e, 1048624,
+	0x2c7e, 0x2c7f, 1037761,
+	0xff21, 0xff3a, 1048608,
+	0x10400, 0x10427, 1048616,
+};
+
+static uint32_t tolowers[] = {
+	0x0100, 1048577,
+	0x0102, 1048577,
+	0x0104, 1048577,
+	0x0106, 1048577,
+	0x0108, 1048577,
+	0x010a, 1048577,
+	0x010c, 1048577,
+	0x010e, 1048577,
+	0x0110, 1048577,
+	0x0112, 1048577,
+	0x0114, 1048577,
+	0x0116, 1048577,
+	0x0118, 1048577,
+	0x011a, 1048577,
+	0x011c, 1048577,
+	0x011e, 1048577,
+	0x0120, 1048577,
+	0x0122, 1048577,
+	0x0124, 1048577,
+	0x0126, 1048577,
+	0x0128, 1048577,
+	0x012a, 1048577,
+	0x012c, 1048577,
+	0x012e, 1048577,
+	0x0130, 1048377,
+	0x0132, 1048577,
+	0x0134, 1048577,
+	0x0136, 1048577,
+	0x0139, 1048577,
+	0x013b, 1048577,
+	0x013d, 1048577,
+	0x013f, 1048577,
+	0x0141, 1048577,
+	0x0143, 1048577,
+	0x0145, 1048577,
+	0x0147, 1048577,
+	0x014a, 1048577,
+	0x014c, 1048577,
+	0x014e, 1048577,
+	0x0150, 1048577,
+	0x0152, 1048577,
+	0x0154, 1048577,
+	0x0156, 1048577,
+	0x0158, 1048577,
+	0x015a, 1048577,
+	0x015c, 1048577,
+	0x015e, 1048577,
+	0x0160, 1048577,
+	0x0162, 1048577,
+	0x0164, 1048577,
+	0x0166, 1048577,
+	0x0168, 1048577,
+	0x016a, 1048577,
+	0x016c, 1048577,
+	0x016e, 1048577,
+	0x0170, 1048577,
+	0x0172, 1048577,
+	0x0174, 1048577,
+	0x0176, 1048577,
+	0x0178, 1048455,
+	0x0179, 1048577,
+	0x017b, 1048577,
+	0x017d, 1048577,
+	0x0181, 1048786,
+	0x0182, 1048577,
+	0x0184, 1048577,
+	0x0186, 1048782,
+	0x0187, 1048577,
+	0x018b, 1048577,
+	0x018e, 1048655,
+	0x018f, 1048778,
+	0x0190, 1048779,
+	0x0191, 1048577,
+	0x0193, 1048781,
+	0x0194, 1048783,
+	0x0196, 1048787,
+	0x0197, 1048785,
+	0x0198, 1048577,
+	0x019c, 1048787,
+	0x019d, 1048789,
+	0x019f, 1048790,
+	0x01a0, 1048577,
+	0x01a2, 1048577,
+	0x01a4, 1048577,
+	0x01a6, 1048794,
+	0x01a7, 1048577,
+	0x01a9, 1048794,
+	0x01ac, 1048577,
+	0x01ae, 1048794,
+	0x01af, 1048577,
+	0x01b3, 1048577,
+	0x01b5, 1048577,
+	0x01b7, 1048795,
+	0x01b8, 1048577,
+	0x01bc, 1048577,
+	0x01c4, 1048578,
+	0x01c5, 1048577,
+	0x01c7, 1048578,
+	0x01c8, 1048577,
+	0x01ca, 1048578,
+	0x01cb, 1048577,
+	0x01cd, 1048577,
+	0x01cf, 1048577,
+	0x01d1, 1048577,
+	0x01d3, 1048577,
+	0x01d5, 1048577,
+	0x01d7, 1048577,
+	0x01d9, 1048577,
+	0x01db, 1048577,
+	0x01de, 1048577,
+	0x01e0, 1048577,
+	0x01e2, 1048577,
+	0x01e4, 1048577,
+	0x01e6, 1048577,
+	0x01e8, 1048577,
+	0x01ea, 1048577,
+	0x01ec, 1048577,
+	0x01ee, 1048577,
+	0x01f1, 1048578,
+	0x01f2, 1048577,
+	0x01f4, 1048577,
+	0x01f6, 1048479,
+	0x01f7, 1048520,
+	0x01f8, 1048577,
+	0x01fa, 1048577,
+	0x01fc, 1048577,
+	0x01fe, 1048577,
+	0x0200, 1048577,
+	0x0202, 1048577,
+	0x0204, 1048577,
+	0x0206, 1048577,
+	0x0208, 1048577,
+	0x020a, 1048577,
+	0x020c, 1048577,
+	0x020e, 1048577,
+	0x0210, 1048577,
+	0x0212, 1048577,
+	0x0214, 1048577,
+	0x0216, 1048577,
+	0x0218, 1048577,
+	0x021a, 1048577,
+	0x021c, 1048577,
+	0x021e, 1048577,
+	0x0220, 1048446,
+	0x0222, 1048577,
+	0x0224, 1048577,
+	0x0226, 1048577,
+	0x0228, 1048577,
+	0x022a, 1048577,
+	0x022c, 1048577,
+	0x022e, 1048577,
+	0x0230, 1048577,
+	0x0232, 1048577,
+	0x023a, 1059371,
+	0x023b, 1048577,
+	0x023d, 1048413,
+	0x023e, 1059368,
+	0x0241, 1048577,
+	0x0243, 1048381,
+	0x0244, 1048645,
+	0x0245, 1048647,
+	0x0246, 1048577,
+	0x0248, 1048577,
+	0x024a, 1048577,
+	0x024c, 1048577,
+	0x024e, 1048577,
+	0x0370, 1048577,
+	0x0372, 1048577,
+	0x0376, 1048577,
+	0x0386, 1048614,
+	0x038c, 1048640,
+	0x03cf, 1048584,
+	0x03d8, 1048577,
+	0x03da, 1048577,
+	0x03dc, 1048577,
+	0x03de, 1048577,
+	0x03e0, 1048577,
+	0x03e2, 1048577,
+	0x03e4, 1048577,
+	0x03e6, 1048577,
+	0x03e8, 1048577,
+	0x03ea, 1048577,
+	0x03ec, 1048577,
+	0x03ee, 1048577,
+	0x03f4, 1048516,
+	0x03f7, 1048577,
+	0x03f9, 1048569,
+	0x03fa, 1048577,
+	0x0460, 1048577,
+	0x0462, 1048577,
+	0x0464, 1048577,
+	0x0466, 1048577,
+	0x0468, 1048577,
+	0x046a, 1048577,
+	0x046c, 1048577,
+	0x046e, 1048577,
+	0x0470, 1048577,
+	0x0472, 1048577,
+	0x0474, 1048577,
+	0x0476, 1048577,
+	0x0478, 1048577,
+	0x047a, 1048577,
+	0x047c, 1048577,
+	0x047e, 1048577,
+	0x0480, 1048577,
+	0x048a, 1048577,
+	0x048c, 1048577,
+	0x048e, 1048577,
+	0x0490, 1048577,
+	0x0492, 1048577,
+	0x0494, 1048577,
+	0x0496, 1048577,
+	0x0498, 1048577,
+	0x049a, 1048577,
+	0x049c, 1048577,
+	0x049e, 1048577,
+	0x04a0, 1048577,
+	0x04a2, 1048577,
+	0x04a4, 1048577,
+	0x04a6, 1048577,
+	0x04a8, 1048577,
+	0x04aa, 1048577,
+	0x04ac, 1048577,
+	0x04ae, 1048577,
+	0x04b0, 1048577,
+	0x04b2, 1048577,
+	0x04b4, 1048577,
+	0x04b6, 1048577,
+	0x04b8, 1048577,
+	0x04ba, 1048577,
+	0x04bc, 1048577,
+	0x04be, 1048577,
+	0x04c0, 1048591,
+	0x04c1, 1048577,
+	0x04c3, 1048577,
+	0x04c5, 1048577,
+	0x04c7, 1048577,
+	0x04c9, 1048577,
+	0x04cb, 1048577,
+	0x04cd, 1048577,
+	0x04d0, 1048577,
+	0x04d2, 1048577,
+	0x04d4, 1048577,
+	0x04d6, 1048577,
+	0x04d8, 1048577,
+	0x04da, 1048577,
+	0x04dc, 1048577,
+	0x04de, 1048577,
+	0x04e0, 1048577,
+	0x04e2, 1048577,
+	0x04e4, 1048577,
+	0x04e6, 1048577,
+	0x04e8, 1048577,
+	0x04ea, 1048577,
+	0x04ec, 1048577,
+	0x04ee, 1048577,
+	0x04f0, 1048577,
+	0x04f2, 1048577,
+	0x04f4, 1048577,
+	0x04f6, 1048577,
+	0x04f8, 1048577,
+	0x04fa, 1048577,
+	0x04fc, 1048577,
+	0x04fe, 1048577,
+	0x0500, 1048577,
+	0x0502, 1048577,
+	0x0504, 1048577,
+	0x0506, 1048577,
+	0x0508, 1048577,
+	0x050a, 1048577,
+	0x050c, 1048577,
+	0x050e, 1048577,
+	0x0510, 1048577,
+	0x0512, 1048577,
+	0x0514, 1048577,
+	0x0516, 1048577,
+	0x0518, 1048577,
+	0x051a, 1048577,
+	0x051c, 1048577,
+	0x051e, 1048577,
+	0x0520, 1048577,
+	0x0522, 1048577,
+	0x0524, 1048577,
+	0x0526, 1048577,
+	0x10c7, 1055840,
+	0x10cd, 1055840,
+	0x1e00, 1048577,
+	0x1e02, 1048577,
+	0x1e04, 1048577,
+	0x1e06, 1048577,
+	0x1e08, 1048577,
+	0x1e0a, 1048577,
+	0x1e0c, 1048577,
+	0x1e0e, 1048577,
+	0x1e10, 1048577,
+	0x1e12, 1048577,
+	0x1e14, 1048577,
+	0x1e16, 1048577,
+	0x1e18, 1048577,
+	0x1e1a, 1048577,
+	0x1e1c, 1048577,
+	0x1e1e, 1048577,
+	0x1e20, 1048577,
+	0x1e22, 1048577,
+	0x1e24, 1048577,
+	0x1e26, 1048577,
+	0x1e28, 1048577,
+	0x1e2a, 1048577,
+	0x1e2c, 1048577,
+	0x1e2e, 1048577,
+	0x1e30, 1048577,
+	0x1e32, 1048577,
+	0x1e34, 1048577,
+	0x1e36, 1048577,
+	0x1e38, 1048577,
+	0x1e3a, 1048577,
+	0x1e3c, 1048577,
+	0x1e3e, 1048577,
+	0x1e40, 1048577,
+	0x1e42, 1048577,
+	0x1e44, 1048577,
+	0x1e46, 1048577,
+	0x1e48, 1048577,
+	0x1e4a, 1048577,
+	0x1e4c, 1048577,
+	0x1e4e, 1048577,
+	0x1e50, 1048577,
+	0x1e52, 1048577,
+	0x1e54, 1048577,
+	0x1e56, 1048577,
+	0x1e58, 1048577,
+	0x1e5a, 1048577,
+	0x1e5c, 1048577,
+	0x1e5e, 1048577,
+	0x1e60, 1048577,
+	0x1e62, 1048577,
+	0x1e64, 1048577,
+	0x1e66, 1048577,
+	0x1e68, 1048577,
+	0x1e6a, 1048577,
+	0x1e6c, 1048577,
+	0x1e6e, 1048577,
+	0x1e70, 1048577,
+	0x1e72, 1048577,
+	0x1e74, 1048577,
+	0x1e76, 1048577,
+	0x1e78, 1048577,
+	0x1e7a, 1048577,
+	0x1e7c, 1048577,
+	0x1e7e, 1048577,
+	0x1e80, 1048577,
+	0x1e82, 1048577,
+	0x1e84, 1048577,
+	0x1e86, 1048577,
+	0x1e88, 1048577,
+	0x1e8a, 1048577,
+	0x1e8c, 1048577,
+	0x1e8e, 1048577,
+	0x1e90, 1048577,
+	0x1e92, 1048577,
+	0x1e94, 1048577,
+	0x1e9e, 1040961,
+	0x1ea0, 1048577,
+	0x1ea2, 1048577,
+	0x1ea4, 1048577,
+	0x1ea6, 1048577,
+	0x1ea8, 1048577,
+	0x1eaa, 1048577,
+	0x1eac, 1048577,
+	0x1eae, 1048577,
+	0x1eb0, 1048577,
+	0x1eb2, 1048577,
+	0x1eb4, 1048577,
+	0x1eb6, 1048577,
+	0x1eb8, 1048577,
+	0x1eba, 1048577,
+	0x1ebc, 1048577,
+	0x1ebe, 1048577,
+	0x1ec0, 1048577,
+	0x1ec2, 1048577,
+	0x1ec4, 1048577,
+	0x1ec6, 1048577,
+	0x1ec8, 1048577,
+	0x1eca, 1048577,
+	0x1ecc, 1048577,
+	0x1ece, 1048577,
+	0x1ed0, 1048577,
+	0x1ed2, 1048577,
+	0x1ed4, 1048577,
+	0x1ed6, 1048577,
+	0x1ed8, 1048577,
+	0x1eda, 1048577,
+	0x1edc, 1048577,
+	0x1ede, 1048577,
+	0x1ee0, 1048577,
+	0x1ee2, 1048577,
+	0x1ee4, 1048577,
+	0x1ee6, 1048577,
+	0x1ee8, 1048577,
+	0x1eea, 1048577,
+	0x1eec, 1048577,
+	0x1eee, 1048577,
+	0x1ef0, 1048577,
+	0x1ef2, 1048577,
+	0x1ef4, 1048577,
+	0x1ef6, 1048577,
+	0x1ef8, 1048577,
+	0x1efa, 1048577,
+	0x1efc, 1048577,
+	0x1efe, 1048577,
+	0x1f59, 1048568,
+	0x1f5b, 1048568,
+	0x1f5d, 1048568,
+	0x1f5f, 1048568,
+	0x1fbc, 1048567,
+	0x1fcc, 1048567,
+	0x1fec, 1048569,
+	0x1ffc, 1048567,
+	0x2126, 1041059,
+	0x212a, 1040193,
+	0x212b, 1040314,
+	0x2132, 1048604,
+	0x2183, 1048577,
+	0x2c60, 1048577,
+	0x2c62, 1037833,
+	0x2c63, 1044762,
+	0x2c64, 1037849,
+	0x2c67, 1048577,
+	0x2c69, 1048577,
+	0x2c6b, 1048577,
+	0x2c6d, 1037796,
+	0x2c6e, 1037827,
+	0x2c6f, 1037793,
+	0x2c70, 1037794,
+	0x2c72, 1048577,
+	0x2c75, 1048577,
+	0x2c80, 1048577,
+	0x2c82, 1048577,
+	0x2c84, 1048577,
+	0x2c86, 1048577,
+	0x2c88, 1048577,
+	0x2c8a, 1048577,
+	0x2c8c, 1048577,
+	0x2c8e, 1048577,
+	0x2c90, 1048577,
+	0x2c92, 1048577,
+	0x2c94, 1048577,
+	0x2c96, 1048577,
+	0x2c98, 1048577,
+	0x2c9a, 1048577,
+	0x2c9c, 1048577,
+	0x2c9e, 1048577,
+	0x2ca0, 1048577,
+	0x2ca2, 1048577,
+	0x2ca4, 1048577,
+	0x2ca6, 1048577,
+	0x2ca8, 1048577,
+	0x2caa, 1048577,
+	0x2cac, 1048577,
+	0x2cae, 1048577,
+	0x2cb0, 1048577,
+	0x2cb2, 1048577,
+	0x2cb4, 1048577,
+	0x2cb6, 1048577,
+	0x2cb8, 1048577,
+	0x2cba, 1048577,
+	0x2cbc, 1048577,
+	0x2cbe, 1048577,
+	0x2cc0, 1048577,
+	0x2cc2, 1048577,
+	0x2cc4, 1048577,
+	0x2cc6, 1048577,
+	0x2cc8, 1048577,
+	0x2cca, 1048577,
+	0x2ccc, 1048577,
+	0x2cce, 1048577,
+	0x2cd0, 1048577,
+	0x2cd2, 1048577,
+	0x2cd4, 1048577,
+	0x2cd6, 1048577,
+	0x2cd8, 1048577,
+	0x2cda, 1048577,
+	0x2cdc, 1048577,
+	0x2cde, 1048577,
+	0x2ce0, 1048577,
+	0x2ce2, 1048577,
+	0x2ceb, 1048577,
+	0x2ced, 1048577,
+	0x2cf2, 1048577,
+	0xa640, 1048577,
+	0xa642, 1048577,
+	0xa644, 1048577,
+	0xa646, 1048577,
+	0xa648, 1048577,
+	0xa64a, 1048577,
+	0xa64c, 1048577,
+	0xa64e, 1048577,
+	0xa650, 1048577,
+	0xa652, 1048577,
+	0xa654, 1048577,
+	0xa656, 1048577,
+	0xa658, 1048577,
+	0xa65a, 1048577,
+	0xa65c, 1048577,
+	0xa65e, 1048577,
+	0xa660, 1048577,
+	0xa662, 1048577,
+	0xa664, 1048577,
+	0xa666, 1048577,
+	0xa668, 1048577,
+	0xa66a, 1048577,
+	0xa66c, 1048577,
+	0xa680, 1048577,
+	0xa682, 1048577,
+	0xa684, 1048577,
+	0xa686, 1048577,
+	0xa688, 1048577,
+	0xa68a, 1048577,
+	0xa68c, 1048577,
+	0xa68e, 1048577,
+	0xa690, 1048577,
+	0xa692, 1048577,
+	0xa694, 1048577,
+	0xa696, 1048577,
+	0xa722, 1048577,
+	0xa724, 1048577,
+	0xa726, 1048577,
+	0xa728, 1048577,
+	0xa72a, 1048577,
+	0xa72c, 1048577,
+	0xa72e, 1048577,
+	0xa732, 1048577,
+	0xa734, 1048577,
+	0xa736, 1048577,
+	0xa738, 1048577,
+	0xa73a, 1048577,
+	0xa73c, 1048577,
+	0xa73e, 1048577,
+	0xa740, 1048577,
+	0xa742, 1048577,
+	0xa744, 1048577,
+	0xa746, 1048577,
+	0xa748, 1048577,
+	0xa74a, 1048577,
+	0xa74c, 1048577,
+	0xa74e, 1048577,
+	0xa750, 1048577,
+	0xa752, 1048577,
+	0xa754, 1048577,
+	0xa756, 1048577,
+	0xa758, 1048577,
+	0xa75a, 1048577,
+	0xa75c, 1048577,
+	0xa75e, 1048577,
+	0xa760, 1048577,
+	0xa762, 1048577,
+	0xa764, 1048577,
+	0xa766, 1048577,
+	0xa768, 1048577,
+	0xa76a, 1048577,
+	0xa76c, 1048577,
+	0xa76e, 1048577,
+	0xa779, 1048577,
+	0xa77b, 1048577,
+	0xa77d, 1013244,
+	0xa77e, 1048577,
+	0xa780, 1048577,
+	0xa782, 1048577,
+	0xa784, 1048577,
+	0xa786, 1048577,
+	0xa78b, 1048577,
+	0xa78d, 1006296,
+	0xa790, 1048577,
+	0xa792, 1048577,
+	0xa7a0, 1048577,
+	0xa7a2, 1048577,
+	0xa7a4, 1048577,
+	0xa7a6, 1048577,
+	0xa7a8, 1048577,
+	0xa7aa, 1006268,
+};
+
+/* }}} */
+
+/* {{{ To title */
+
+static uint32_t totitler[] = {
+	0x0061, 0x007a, 1048544,
+	0x00e0, 0x00f6, 1048544,
+	0x00f8, 0x00fe, 1048544,
+	0x023f, 0x0240, 1059391,
+	0x0256, 0x0257, 1048371,
+	0x028a, 0x028b, 1048359,
+	0x037b, 0x037d, 1048706,
+	0x03ad, 0x03af, 1048539,
+	0x03b1, 0x03c1, 1048544,
+	0x03c3, 0x03cb, 1048544,
+	0x03cd, 0x03ce, 1048513,
+	0x0430, 0x044f, 1048544,
+	0x0450, 0x045f, 1048496,
+	0x0561, 0x0586, 1048528,
+	0x1f00, 0x1f07, 1048584,
+	0x1f10, 0x1f15, 1048584,
+	0x1f20, 0x1f27, 1048584,
+	0x1f30, 0x1f37, 1048584,
+	0x1f40, 0x1f45, 1048584,
+	0x1f60, 0x1f67, 1048584,
+	0x1f70, 0x1f71, 1048650,
+	0x1f72, 0x1f75, 1048662,
+	0x1f76, 0x1f77, 1048676,
+	0x1f78, 0x1f79, 1048704,
+	0x1f7a, 0x1f7b, 1048688,
+	0x1f7c, 0x1f7d, 1048702,
+	0x1f80, 0x1f87, 1048584,
+	0x1f90, 0x1f97, 1048584,
+	0x1fa0, 0x1fa7, 1048584,
+	0x1fb0, 0x1fb1, 1048584,
+	0x1fd0, 0x1fd1, 1048584,
+	0x1fe0, 0x1fe1, 1048584,
+	0x2170, 0x217f, 1048560,
+	0x24d0, 0x24e9, 1048550,
+	0x2c30, 0x2c5e, 1048528,
+	0x2d00, 0x2d25, 1041312,
+	0xff41, 0xff5a, 1048544,
+	0x10428, 0x1044f, 1048536,
+};
+
+static uint32_t totitles[] = {
+	0x00b5, 1049319,
+	0x00ff, 1048697,
+	0x0101, 1048575,
+	0x0103, 1048575,
+	0x0105, 1048575,
+	0x0107, 1048575,
+	0x0109, 1048575,
+	0x010b, 1048575,
+	0x010d, 1048575,
+	0x010f, 1048575,
+	0x0111, 1048575,
+	0x0113, 1048575,
+	0x0115, 1048575,
+	0x0117, 1048575,
+	0x0119, 1048575,
+	0x011b, 1048575,
+	0x011d, 1048575,
+	0x011f, 1048575,
+	0x0121, 1048575,
+	0x0123, 1048575,
+	0x0125, 1048575,
+	0x0127, 1048575,
+	0x0129, 1048575,
+	0x012b, 1048575,
+	0x012d, 1048575,
+	0x012f, 1048575,
+	0x0131, 1048344,
+	0x0133, 1048575,
+	0x0135, 1048575,
+	0x0137, 1048575,
+	0x013a, 1048575,
+	0x013c, 1048575,
+	0x013e, 1048575,
+	0x0140, 1048575,
+	0x0142, 1048575,
+	0x0144, 1048575,
+	0x0146, 1048575,
+	0x0148, 1048575,
+	0x014b, 1048575,
+	0x014d, 1048575,
+	0x014f, 1048575,
+	0x0151, 1048575,
+	0x0153, 1048575,
+	0x0155, 1048575,
+	0x0157, 1048575,
+	0x0159, 1048575,
+	0x015b, 1048575,
+	0x015d, 1048575,
+	0x015f, 1048575,
+	0x0161, 1048575,
+	0x0163, 1048575,
+	0x0165, 1048575,
+	0x0167, 1048575,
+	0x0169, 1048575,
+	0x016b, 1048575,
+	0x016d, 1048575,
+	0x016f, 1048575,
+	0x0171, 1048575,
+	0x0173, 1048575,
+	0x0175, 1048575,
+	0x0177, 1048575,
+	0x017a, 1048575,
+	0x017c, 1048575,
+	0x017e, 1048575,
+	0x017f, 1048276,
+	0x0180, 1048771,
+	0x0183, 1048575,
+	0x0185, 1048575,
+	0x0188, 1048575,
+	0x018c, 1048575,
+	0x0192, 1048575,
+	0x0195, 1048673,
+	0x0199, 1048575,
+	0x019a, 1048739,
+	0x019e, 1048706,
+	0x01a1, 1048575,
+	0x01a3, 1048575,
+	0x01a5, 1048575,
+	0x01a8, 1048575,
+	0x01ad, 1048575,
+	0x01b0, 1048575,
+	0x01b4, 1048575,
+	0x01b6, 1048575,
+	0x01b9, 1048575,
+	0x01bd, 1048575,
+	0x01bf, 1048632,
+	0x01c4, 1048577,
+	0x01c6, 1048575,
+	0x01c7, 1048577,
+	0x01c9, 1048575,
+	0x01ca, 1048577,
+	0x01cc, 1048575,
+	0x01ce, 1048575,
+	0x01d0, 1048575,
+	0x01d2, 1048575,
+	0x01d4, 1048575,
+	0x01d6, 1048575,
+	0x01d8, 1048575,
+	0x01da, 1048575,
+	0x01dc, 1048575,
+	0x01dd, 1048497,
+	0x01df, 1048575,
+	0x01e1, 1048575,
+	0x01e3, 1048575,
+	0x01e5, 1048575,
+	0x01e7, 1048575,
+	0x01e9, 1048575,
+	0x01eb, 1048575,
+	0x01ed, 1048575,
+	0x01ef, 1048575,
+	0x01f1, 1048577,
+	0x01f3, 1048575,
+	0x01f5, 1048575,
+	0x01f9, 1048575,
+	0x01fb, 1048575,
+	0x01fd, 1048575,
+	0x01ff, 1048575,
+	0x0201, 1048575,
+	0x0203, 1048575,
+	0x0205, 1048575,
+	0x0207, 1048575,
+	0x0209, 1048575,
+	0x020b, 1048575,
+	0x020d, 1048575,
+	0x020f, 1048575,
+	0x0211, 1048575,
+	0x0213, 1048575,
+	0x0215, 1048575,
+	0x0217, 1048575,
+	0x0219, 1048575,
+	0x021b, 1048575,
+	0x021d, 1048575,
+	0x021f, 1048575,
+	0x0223, 1048575,
+	0x0225, 1048575,
+	0x0227, 1048575,
+	0x0229, 1048575,
+	0x022b, 1048575,
+	0x022d, 1048575,
+	0x022f, 1048575,
+	0x0231, 1048575,
+	0x0233, 1048575,
+	0x023c, 1048575,
+	0x0242, 1048575,
+	0x0247, 1048575,
+	0x0249, 1048575,
+	0x024b, 1048575,
+	0x024d, 1048575,
+	0x024f, 1048575,
+	0x0250, 1059359,
+	0x0251, 1059356,
+	0x0252, 1059358,
+	0x0253, 1048366,
+	0x0254, 1048370,
+	0x0259, 1048374,
+	0x025b, 1048373,
+	0x0260, 1048371,
+	0x0263, 1048369,
+	0x0265, 1090856,
+	0x0266, 1090884,
+	0x0268, 1048367,
+	0x0269, 1048365,
+	0x026b, 1059319,
+	0x026f, 1048365,
+	0x0271, 1059325,
+	0x0272, 1048363,
+	0x0275, 1048362,
+	0x027d, 1059303,
+	0x0280, 1048358,
+	0x0283, 1048358,
+	0x0288, 1048358,
+	0x0289, 1048507,
+	0x028c, 1048505,
+	0x0292, 1048357,
+	0x0345, 1048660,
+	0x0371, 1048575,
+	0x0373, 1048575,
+	0x0377, 1048575,
+	0x03ac, 1048538,
+	0x03c2, 1048545,
+	0x03cc, 1048512,
+	0x03d0, 1048514,
+	0x03d1, 1048519,
+	0x03d5, 1048529,
+	0x03d6, 1048522,
+	0x03d7, 1048568,
+	0x03d9, 1048575,
+	0x03db, 1048575,
+	0x03dd, 1048575,
+	0x03df, 1048575,
+	0x03e1, 1048575,
+	0x03e3, 1048575,
+	0x03e5, 1048575,
+	0x03e7, 1048575,
+	0x03e9, 1048575,
+	0x03eb, 1048575,
+	0x03ed, 1048575,
+	0x03ef, 1048575,
+	0x03f0, 1048490,
+	0x03f1, 1048496,
+	0x03f2, 1048583,
+	0x03f5, 1048480,
+	0x03f8, 1048575,
+	0x03fb, 1048575,
+	0x0461, 1048575,
+	0x0463, 1048575,
+	0x0465, 1048575,
+	0x0467, 1048575,
+	0x0469, 1048575,
+	0x046b, 1048575,
+	0x046d, 1048575,
+	0x046f, 1048575,
+	0x0471, 1048575,
+	0x0473, 1048575,
+	0x0475, 1048575,
+	0x0477, 1048575,
+	0x0479, 1048575,
+	0x047b, 1048575,
+	0x047d, 1048575,
+	0x047f, 1048575,
+	0x0481, 1048575,
+	0x048b, 1048575,
+	0x048d, 1048575,
+	0x048f, 1048575,
+	0x0491, 1048575,
+	0x0493, 1048575,
+	0x0495, 1048575,
+	0x0497, 1048575,
+	0x0499, 1048575,
+	0x049b, 1048575,
+	0x049d, 1048575,
+	0x049f, 1048575,
+	0x04a1, 1048575,
+	0x04a3, 1048575,
+	0x04a5, 1048575,
+	0x04a7, 1048575,
+	0x04a9, 1048575,
+	0x04ab, 1048575,
+	0x04ad, 1048575,
+	0x04af, 1048575,
+	0x04b1, 1048575,
+	0x04b3, 1048575,
+	0x04b5, 1048575,
+	0x04b7, 1048575,
+	0x04b9, 1048575,
+	0x04bb, 1048575,
+	0x04bd, 1048575,
+	0x04bf, 1048575,
+	0x04c2, 1048575,
+	0x04c4, 1048575,
+	0x04c6, 1048575,
+	0x04c8, 1048575,
+	0x04ca, 1048575,
+	0x04cc, 1048575,
+	0x04ce, 1048575,
+	0x04cf, 1048561,
+	0x04d1, 1048575,
+	0x04d3, 1048575,
+	0x04d5, 1048575,
+	0x04d7, 1048575,
+	0x04d9, 1048575,
+	0x04db, 1048575,
+	0x04dd, 1048575,
+	0x04df, 1048575,
+	0x04e1, 1048575,
+	0x04e3, 1048575,
+	0x04e5, 1048575,
+	0x04e7, 1048575,
+	0x04e9, 1048575,
+	0x04eb, 1048575,
+	0x04ed, 1048575,
+	0x04ef, 1048575,
+	0x04f1, 1048575,
+	0x04f3, 1048575,
+	0x04f5, 1048575,
+	0x04f7, 1048575,
+	0x04f9, 1048575,
+	0x04fb, 1048575,
+	0x04fd, 1048575,
+	0x04ff, 1048575,
+	0x0501, 1048575,
+	0x0503, 1048575,
+	0x0505, 1048575,
+	0x0507, 1048575,
+	0x0509, 1048575,
+	0x050b, 1048575,
+	0x050d, 1048575,
+	0x050f, 1048575,
+	0x0511, 1048575,
+	0x0513, 1048575,
+	0x0515, 1048575,
+	0x0517, 1048575,
+	0x0519, 1048575,
+	0x051b, 1048575,
+	0x051d, 1048575,
+	0x051f, 1048575,
+	0x0521, 1048575,
+	0x0523, 1048575,
+	0x0525, 1048575,
+	0x0527, 1048575,
+	0x1d79, 1083908,
+	0x1d7d, 1052390,
+	0x1e01, 1048575,
+	0x1e03, 1048575,
+	0x1e05, 1048575,
+	0x1e07, 1048575,
+	0x1e09, 1048575,
+	0x1e0b, 1048575,
+	0x1e0d, 1048575,
+	0x1e0f, 1048575,
+	0x1e11, 1048575,
+	0x1e13, 1048575,
+	0x1e15, 1048575,
+	0x1e17, 1048575,
+	0x1e19, 1048575,
+	0x1e1b, 1048575,
+	0x1e1d, 1048575,
+	0x1e1f, 1048575,
+	0x1e21, 1048575,
+	0x1e23, 1048575,
+	0x1e25, 1048575,
+	0x1e27, 1048575,
+	0x1e29, 1048575,
+	0x1e2b, 1048575,
+	0x1e2d, 1048575,
+	0x1e2f, 1048575,
+	0x1e31, 1048575,
+	0x1e33, 1048575,
+	0x1e35, 1048575,
+	0x1e37, 1048575,
+	0x1e39, 1048575,
+	0x1e3b, 1048575,
+	0x1e3d, 1048575,
+	0x1e3f, 1048575,
+	0x1e41, 1048575,
+	0x1e43, 1048575,
+	0x1e45, 1048575,
+	0x1e47, 1048575,
+	0x1e49, 1048575,
+	0x1e4b, 1048575,
+	0x1e4d, 1048575,
+	0x1e4f, 1048575,
+	0x1e51, 1048575,
+	0x1e53, 1048575,
+	0x1e55, 1048575,
+	0x1e57, 1048575,
+	0x1e59, 1048575,
+	0x1e5b, 1048575,
+	0x1e5d, 1048575,
+	0x1e5f, 1048575,
+	0x1e61, 1048575,
+	0x1e63, 1048575,
+	0x1e65, 1048575,
+	0x1e67, 1048575,
+	0x1e69, 1048575,
+	0x1e6b, 1048575,
+	0x1e6d, 1048575,
+	0x1e6f, 1048575,
+	0x1e71, 1048575,
+	0x1e73, 1048575,
+	0x1e75, 1048575,
+	0x1e77, 1048575,
+	0x1e79, 1048575,
+	0x1e7b, 1048575,
+	0x1e7d, 1048575,
+	0x1e7f, 1048575,
+	0x1e81, 1048575,
+	0x1e83, 1048575,
+	0x1e85, 1048575,
+	0x1e87, 1048575,
+	0x1e89, 1048575,
+	0x1e8b, 1048575,
+	0x1e8d, 1048575,
+	0x1e8f, 1048575,
+	0x1e91, 1048575,
+	0x1e93, 1048575,
+	0x1e95, 1048575,
+	0x1e9b, 1048517,
+	0x1ea1, 1048575,
+	0x1ea3, 1048575,
+	0x1ea5, 1048575,
+	0x1ea7, 1048575,
+	0x1ea9, 1048575,
+	0x1eab, 1048575,
+	0x1ead, 1048575,
+	0x1eaf, 1048575,
+	0x1eb1, 1048575,
+	0x1eb3, 1048575,
+	0x1eb5, 1048575,
+	0x1eb7, 1048575,
+	0x1eb9, 1048575,
+	0x1ebb, 1048575,
+	0x1ebd, 1048575,
+	0x1ebf, 1048575,
+	0x1ec1, 1048575,
+	0x1ec3, 1048575,
+	0x1ec5, 1048575,
+	0x1ec7, 1048575,
+	0x1ec9, 1048575,
+	0x1ecb, 1048575,
+	0x1ecd, 1048575,
+	0x1ecf, 1048575,
+	0x1ed1, 1048575,
+	0x1ed3, 1048575,
+	0x1ed5, 1048575,
+	0x1ed7, 1048575,
+	0x1ed9, 1048575,
+	0x1edb, 1048575,
+	0x1edd, 1048575,
+	0x1edf, 1048575,
+	0x1ee1, 1048575,
+	0x1ee3, 1048575,
+	0x1ee5, 1048575,
+	0x1ee7, 1048575,
+	0x1ee9, 1048575,
+	0x1eeb, 1048575,
+	0x1eed, 1048575,
+	0x1eef, 1048575,
+	0x1ef1, 1048575,
+	0x1ef3, 1048575,
+	0x1ef5, 1048575,
+	0x1ef7, 1048575,
+	0x1ef9, 1048575,
+	0x1efb, 1048575,
+	0x1efd, 1048575,
+	0x1eff, 1048575,
+	0x1f51, 1048584,
+	0x1f53, 1048584,
+	0x1f55, 1048584,
+	0x1f57, 1048584,
+	0x1fb3, 1048585,
+	0x1fbe, 1041371,
+	0x1fc3, 1048585,
+	0x1fe5, 1048583,
+	0x1ff3, 1048585,
+	0x214e, 1048548,
+	0x2184, 1048575,
+	0x2c61, 1048575,
+	0x2c65, 1037781,
+	0x2c66, 1037784,
+	0x2c68, 1048575,
+	0x2c6a, 1048575,
+	0x2c6c, 1048575,
+	0x2c73, 1048575,
+	0x2c76, 1048575,
+	0x2c81, 1048575,
+	0x2c83, 1048575,
+	0x2c85, 1048575,
+	0x2c87, 1048575,
+	0x2c89, 1048575,
+	0x2c8b, 1048575,
+	0x2c8d, 1048575,
+	0x2c8f, 1048575,
+	0x2c91, 1048575,
+	0x2c93, 1048575,
+	0x2c95, 1048575,
+	0x2c97, 1048575,
+	0x2c99, 1048575,
+	0x2c9b, 1048575,
+	0x2c9d, 1048575,
+	0x2c9f, 1048575,
+	0x2ca1, 1048575,
+	0x2ca3, 1048575,
+	0x2ca5, 1048575,
+	0x2ca7, 1048575,
+	0x2ca9, 1048575,
+	0x2cab, 1048575,
+	0x2cad, 1048575,
+	0x2caf, 1048575,
+	0x2cb1, 1048575,
+	0x2cb3, 1048575,
+	0x2cb5, 1048575,
+	0x2cb7, 1048575,
+	0x2cb9, 1048575,
+	0x2cbb, 1048575,
+	0x2cbd, 1048575,
+	0x2cbf, 1048575,
+	0x2cc1, 1048575,
+	0x2cc3, 1048575,
+	0x2cc5, 1048575,
+	0x2cc7, 1048575,
+	0x2cc9, 1048575,
+	0x2ccb, 1048575,
+	0x2ccd, 1048575,
+	0x2ccf, 1048575,
+	0x2cd1, 1048575,
+	0x2cd3, 1048575,
+	0x2cd5, 1048575,
+	0x2cd7, 1048575,
+	0x2cd9, 1048575,
+	0x2cdb, 1048575,
+	0x2cdd, 1048575,
+	0x2cdf, 1048575,
+	0x2ce1, 1048575,
+	0x2ce3, 1048575,
+	0x2cec, 1048575,
+	0x2cee, 1048575,
+	0x2cf3, 1048575,
+	0x2d27, 1041312,
+	0x2d2d, 1041312,
+	0xa641, 1048575,
+	0xa643, 1048575,
+	0xa645, 1048575,
+	0xa647, 1048575,
+	0xa649, 1048575,
+	0xa64b, 1048575,
+	0xa64d, 1048575,
+	0xa64f, 1048575,
+	0xa651, 1048575,
+	0xa653, 1048575,
+	0xa655, 1048575,
+	0xa657, 1048575,
+	0xa659, 1048575,
+	0xa65b, 1048575,
+	0xa65d, 1048575,
+	0xa65f, 1048575,
+	0xa661, 1048575,
+	0xa663, 1048575,
+	0xa665, 1048575,
+	0xa667, 1048575,
+	0xa669, 1048575,
+	0xa66b, 1048575,
+	0xa66d, 1048575,
+	0xa681, 1048575,
+	0xa683, 1048575,
+	0xa685, 1048575,
+	0xa687, 1048575,
+	0xa689, 1048575,
+	0xa68b, 1048575,
+	0xa68d, 1048575,
+	0xa68f, 1048575,
+	0xa691, 1048575,
+	0xa693, 1048575,
+	0xa695, 1048575,
+	0xa697, 1048575,
+	0xa723, 1048575,
+	0xa725, 1048575,
+	0xa727, 1048575,
+	0xa729, 1048575,
+	0xa72b, 1048575,
+	0xa72d, 1048575,
+	0xa72f, 1048575,
+	0xa733, 1048575,
+	0xa735, 1048575,
+	0xa737, 1048575,
+	0xa739, 1048575,
+	0xa73b, 1048575,
+	0xa73d, 1048575,
+	0xa73f, 1048575,
+	0xa741, 1048575,
+	0xa743, 1048575,
+	0xa745, 1048575,
+	0xa747, 1048575,
+	0xa749, 1048575,
+	0xa74b, 1048575,
+	0xa74d, 1048575,
+	0xa74f, 1048575,
+	0xa751, 1048575,
+	0xa753, 1048575,
+	0xa755, 1048575,
+	0xa757, 1048575,
+	0xa759, 1048575,
+	0xa75b, 1048575,
+	0xa75d, 1048575,
+	0xa75f, 1048575,
+	0xa761, 1048575,
+	0xa763, 1048575,
+	0xa765, 1048575,
+	0xa767, 1048575,
+	0xa769, 1048575,
+	0xa76b, 1048575,
+	0xa76d, 1048575,
+	0xa76f, 1048575,
+	0xa77a, 1048575,
+	0xa77c, 1048575,
+	0xa77f, 1048575,
+	0xa781, 1048575,
+	0xa783, 1048575,
+	0xa785, 1048575,
+	0xa787, 1048575,
+	0xa78c, 1048575,
+	0xa791, 1048575,
+	0xa793, 1048575,
+	0xa7a1, 1048575,
+	0xa7a3, 1048575,
+	0xa7a5, 1048575,
+	0xa7a7, 1048575,
+	0xa7a9, 1048575,
+};
+
+/* }}} */
+
+}
+
+void Utf8::encode(uint32_t c, char res[5])
+{
+	switch (nbytesPoint(c)) {
+	case 1:
+		res[0] = c;
+		res[1] = '\0';
+		break;
+	case 2:
+		res[0] = 0xC0 | ((c >> 6)  & 0x1F);
+		res[1] = 0x80 | (c & 0x3F);
+		res[2] = '\0';
+		break;
+	case 3:
+		res[0] = 0xE0 | ((c >> 12) & 0xF );
+		res[1] = 0x80 | ((c >> 6)  & 0x3F);
+		res[2] = 0x80 | (c & 0x3F);
+		res[3] = '\0';
+		break;
+	case 4:
+		res[0] = 0xF0 | ((c >> 18) & 0x7 );
+		res[1] = 0x80 | ((c >> 12) & 0x3F);
+		res[2] = 0x80 | ((c >> 6)  & 0x3F);
+		res[3] = 0x80 | (c & 0x3F);
+		res[4] = '\0';
+		break;
+	default:
+		break;
+	}
+}
+
+void Utf8::decode(uint32_t &c, const char *res)
+{
+	switch (nbytesUtf8(res[0])) {
+	case 1:
+		c = res[0];
+		break;
+	case 2:
+		c = res[0] & 0x1F;
+		c = (c << 6) | (res[1] & 0x3F);
+		break;
+	case 3:
+		c = res[0] & 0x1F;
+		c = (c << 6) | (res[1] & 0x3F);
+		c = (c << 6) | (res[2] & 0x3F);
+		break;
+	case 4:
+		c = res[0] & 0x1F;
+		c = (c << 6) | (res[1] & 0x3F);
+		c = (c << 6) | (res[2] & 0x3F);
+		c = (c << 6) | (res[3] & 0x3F);
+		break;
+	default:
+		break;
+	}
+}
+
+int8_t Utf8::nbytesUtf8(uint8_t c)
+{
+	if (c <= 0x7F)
+		return 1;
+	if ((c & 0xE0) == 0xC0)
+		return 2;
+	if ((c & 0xF0) == 0xE0)
+		return 3;
+	if ((c & 0xF8) == 0xF0)
+		return 4;
+
+	return -1;
+}
+
+int8_t Utf8::nbytesPoint(uint32_t c)
+{
+	if (c <= 0x7F)
+		return 1;
+	if (c <= 0x7FF)
+		return 2;
+	if (c <= 0xFFFF)
+		return 3;
+	if (c <= 0x1FFFFF)
+		return 4;
+
+	return -1;
+}
+
+size_t Utf8::length(const std::string &str)
+{
+	size_t total = 0;
+
+	for (size_t i = 0; i < str.size(); ) {
+		auto size = nbytesUtf8(str[i]);
+
+		if (size < 0)
+			throw std::invalid_argument("invalid sequence");
+
+		total ++;
+		i += size;
+	}
+
+	return total;
+}
+
+std::string Utf8::toutf8(const std::u32string &array)
+{
+	std::string res;
+
+	for (size_t i = 0; i < array.size(); ++i) {
+		char tmp[5];
+		auto size = nbytesPoint(array[i]);
+
+		if (size < 0)
+			throw std::invalid_argument("invalid sequence");
+
+		encode(array[i], tmp);
+		res.insert(res.length(), tmp);
+	}
+
+	return res;
+}
+
+std::u32string Utf8::toutf32(const std::string &str)
+{
+	std::u32string res;
+
+	for (size_t i = 0; i < str.size(); ) {
+		uint32_t point;
+		auto size = nbytesUtf8(str[i]);
+
+		if (size < 0)
+			throw std::invalid_argument("invalid sequence");
+
+		decode(point, str.data() + i);
+		res.push_back(point);
+		i += size;
+	}
+
+	return res;
+}
+
+bool Utf8::isspace(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, isspacer, LEN(isspacer) / 2, 2);
+	if (p && c >= p[0] && c <= p[1])
+		return true;
+
+	return false;
+}
+
+bool Utf8::isdigit(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, isdigitr, LEN(isdigitr) / 2, 2);
+	if (p && c >= p[0] && c <= p[1])
+		return true;
+
+	return false;
+}
+
+bool Utf8::isletter(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, isalphar, LEN(isalphar) / 2, 2);
+	if (p && c >= p[0] && c <= p[1])
+		return true;
+
+	p = rbsearch(c, isalphas, LEN(isalphas), 1);
+	if (p && c == p[0])
+		return true;
+
+	return false;
+}
+
+bool Utf8::isupper(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, isupperr, LEN(isupperr) / 2, 2);
+	if (p && c >= p[0] && c <= p[1])
+		return true;
+
+	p = rbsearch(c, isuppers, LEN(isuppers), 1);
+	if (p && c == p[0])
+		return true;
+
+	return false;
+}
+
+bool Utf8::islower(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, islowerr, LEN(islowerr) / 2, 2);
+	if (p && c >= p[0] && c <= p[1])
+		return true;
+
+	p = rbsearch(c, islowers, LEN(islowers), 1);
+	if (p && c == p[0])
+		return true;
+
+	return false;
+}
+
+bool Utf8::istitle(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, istitler, LEN(istitler) / 2, 2);
+	if (p && c >= p[0] && c <= p[1])
+		return true;
+
+	p = rbsearch(c, istitles, LEN(istitles), 1);
+	if(p && c == p[0])
+		return true;
+
+	return false;
+}
+
+uint32_t Utf8::toupper(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, toupperr, LEN(toupperr) / 3, 3);
+	if (p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+
+	p = rbsearch(c, touppers, LEN(touppers) / 2, 2);
+	if (p && c == p[0])
+		return c + p[1] - 1048576;
+
+	return c;
+}
+
+uint32_t Utf8::tolower(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, tolowerr, LEN(tolowerr) / 3, 3);
+	if (p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+
+	p = rbsearch(c, tolowers, LEN(tolowers) / 2, 2);
+	if (p && c == p[0])
+		return c + p[1] - 1048576;
+	
+	return c;
+}
+
+uint32_t Utf8::totitle(uint32_t c)
+{
+	uint32_t *p;
+
+	p = rbsearch(c, totitler, LEN(totitler) / 3, 3);
+	if (p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+
+	p = rbsearch(c, totitles, LEN(totitles) / 2, 2);
+	if (p && c == p[0])
+		return c + p[1] - 1048576;
+
+	return c;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Utf8/Utf8.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,212 @@
+/*
+ * Utf8.h -- UTF-8 to UTF-32 conversions
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _UTF8_H_
+#define _UTF8_H_
+
+/**
+ * @file Utf8.h
+ * @brief UTF-8 to UTF-32 conversions
+ */
+
+#include <cstdint>
+#include <stdexcept>
+#include <string>
+
+/**
+ * @class Utf8
+ * @brief Conversion between UTF-8 and UTF-32
+ */
+class Utf8 {
+private:
+	static void encode(uint32_t point, char res[5]);
+	static void decode(uint32_t &c, const char *res);
+
+public:
+	/**
+	 * Get the number of bytes for the first multi byte character from a
+	 * utf-8 string.
+	 *
+	 * @param c the first multi byte character
+	 * @return the number of bytes [1-4] or -1 on invalid
+	 */
+	static int8_t nbytesUtf8(uint8_t c);
+
+	/**
+	 * Get the number of bytes for the unicode point.
+	 *
+	 * @param point the unicode point
+	 * @return the number of bytes [1-4] or -1 on invalid
+	 */
+	static int8_t nbytesPoint(uint32_t point);
+
+	/**
+	 * Get real number of character in a string.
+	 *
+	 * @param str the string
+	 * @return the length
+	 * @throw std::invalid_argument on invalid sequence
+	 */
+	static size_t length(const std::string &str);
+
+	/**
+	 * Convert a UTF-32 string to UTF-8 string.
+	 *
+	 * @param array the UTF-32 string
+	 * @return the UTF-8 string
+	 * @throw std::invalid_argument on invalid sequence
+	 */
+	static std::string toutf8(const std::u32string &array);
+
+	/**
+	 * Convert a UTF-8 string to UTF-32 string.
+	 *
+	 * @param str the UTF-8 string
+	 * @return the UTF-32 string
+	 * @throw std::invalid_argument on invalid sequence
+	 */
+	static std::u32string toutf32(const std::string &str);
+
+	/**
+	 * Check if the unicode character is space.
+	 *
+	 * @param c the character
+	 * @return true if space
+	 */
+	static bool isspace(uint32_t c);
+
+	/**
+	 * Check if the unicode character is digit.
+	 *
+	 * @param c the character
+	 * @return true if digit
+	 */
+	static bool isdigit(uint32_t c);
+
+	/**
+	 * Check if the unicode character is letter.
+	 *
+	 * @param c the character
+	 * @return true if letter
+	 */
+	static bool isletter(uint32_t c);
+
+	/**
+	 * Check if the unicode character is upper case.
+	 *
+	 * @param c the character
+	 * @return true if upper case
+	 */
+	static bool isupper(uint32_t c);
+
+	/**
+	 * Check if the unicode character is lower case.
+	 *
+	 * @param c the character
+	 * @return true if lower case
+	 */
+	static bool islower(uint32_t c);
+
+	/**
+	 * Check if the unicode character is title case.
+	 *
+	 * @param c the character
+	 * @return true if title case
+	 */
+	static bool istitle(uint32_t c);
+
+	/**
+	 * Convert to upper case.
+	 *
+	 * @param c the character
+	 * @return the upper case character
+	 */
+	static uint32_t toupper(uint32_t c);
+
+	/**
+	 * Convert to lower case.
+	 *
+	 * @param c the character
+	 * @return the lower case character
+	 */
+	static uint32_t tolower(uint32_t c);
+
+	/**
+	 * Convert to title case.
+	 *
+	 * @param c the character
+	 * @return the title case character
+	 */
+	static uint32_t totitle(uint32_t c);
+
+	/**
+	 * Convert the UTF-8 string to upper case.
+	 *
+	 * @param str the str
+	 * @return the upper case string
+	 */
+	static inline std::string toupper(const std::string &str)
+	{
+		return toutf8(toupper(toutf32(str)));
+	}
+
+	/**
+	 * Convert the UTF-32 string to upper case.
+	 *
+	 * @param str the str
+	 * @return the upper case string
+	 */
+	static inline std::u32string toupper(const std::u32string &str)
+	{
+		auto copy = str;
+
+		for (size_t i = 0; i < str.size(); ++i)
+			copy[i] = toupper(str[i]);
+
+		return copy;
+	}
+
+	/**
+	 * Convert the UTF-8 string to lower case.
+	 *
+	 * @param str the str
+	 * @return the lower case string
+	 */
+	static inline std::string tolower(const std::string &str)
+	{
+		return toutf8(tolower(toutf32(str)));
+	}
+
+	/**
+	 * Convert the UTF-32 string to lower case.
+	 *
+	 * @param str the str
+	 * @return the lower case string
+	 */
+	static inline std::u32string tolower(const std::u32string &str)
+	{
+		auto copy = str;
+
+		for (size_t i = 0; i < str.size(); ++i)
+			copy[i] = tolower(str[i]);
+
+		return copy;
+	}
+};
+
+#endif // !_UTF8_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Xdg/Xdg.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,125 @@
+/*
+ * Xdg.cpp -- XDG directory specifications
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cstdlib>
+#include <stdexcept>
+#include <sstream>
+
+#include "Xdg.h"
+
+namespace {
+
+bool isabsolute(const std::string &path)
+{
+	return path.length() > 0 && path[0] == '/';
+}
+
+std::vector<std::string> split(const std::string &arg)
+{
+	std::stringstream iss(arg);
+	std::string item;
+	std::vector<std::string> elems;
+
+	while (std::getline(iss, item, ':'))
+		if (isabsolute(item))
+			elems.push_back(item);
+
+	return elems;
+}
+
+std::string envOrHome(const std::string &var, const std::string &repl)
+{
+	auto value = getenv(var.c_str());
+
+	if (value == nullptr || !isabsolute(value)) {
+		auto home = getenv("HOME");
+
+		if (home == nullptr)
+			throw std::runtime_error("could not get home directory");
+
+		return std::string(home) + "/" + repl;
+	}
+
+	return value;
+}
+
+std::vector<std::string> listOrDefaults(const std::string &var, const std::vector<std::string> &list)
+{
+	auto value = getenv(var.c_str());
+
+	if (!value)
+		return list;
+
+	// No valid item at all? Use defaults
+	auto result = split(value);
+
+	return (result.size() == 0) ? list : result;
+}
+
+} // !namespace
+
+Xdg::Xdg()
+{
+	m_configHome	= envOrHome("XDG_CONFIG_HOME", ".config");
+	m_dataHome	= envOrHome("XDG_DATA_HOME", ".local/share");
+	m_cacheHome	= envOrHome("XDG_CACHE_HOME", ".cache");
+
+	m_configDirs	= listOrDefaults("XDG_CONFIG_DIRS", { "/etc/xdg" });
+	m_dataDirs	= listOrDefaults("XDG_DATA_DIRS", { "/usr/local/share", "/usr/share" });
+
+	/*
+	 * Runtime directory is a special case and does not have a replacement, the
+	 * application should manage this by itself.
+	 */
+	auto runtime = getenv("XDG_RUNTIME_DIR");
+	if (runtime && isabsolute(runtime))
+		m_runtimeDir = runtime;
+}
+
+const std::string &Xdg::configHome() const noexcept
+{
+	return m_configHome;
+}
+
+const std::string &Xdg::dataHome() const noexcept
+{
+	return m_dataHome;
+}
+
+const std::string &Xdg::cacheHome() const noexcept
+{
+	return m_cacheHome;
+}
+
+const std::string &Xdg::runtimeDir() const
+{
+	if (m_runtimeDir.size() == 0)
+		throw std::runtime_error("XDG_RUNTIME_DIR is not set");
+
+	return m_runtimeDir;
+}
+
+const Xdg::List &Xdg::configDirs() const noexcept
+{
+	return m_configDirs;
+}
+
+const Xdg::List &Xdg::dataDirs() const noexcept
+{
+	return m_dataDirs;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Xdg/Xdg.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,110 @@
+/*
+ * Xdg.h -- XDG directory specifications
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _XDG_H_
+#define _XDG_H_
+
+#include <vector>
+#include <string>
+
+#if defined(_WIN32)
+#  if defined(BUILDING_DLL)
+#    define EXPORT __declspec(dllexport)
+#  else
+#    define EXPORT __declspec(dllimport)
+#  endif
+#else
+#  define EXPORT
+#endif
+
+/**
+ * @class Xdg
+ * @brief XDG specifications
+ *
+ * Read and get XDG directories. This file contains exports thingies so it can
+ * compiles successfully on Windows but its usage is discouraged.
+ */
+class EXPORT Xdg {
+public:
+	using List	= std::vector<std::string>;
+
+private:
+	std::string	m_configHome;
+	std::string	m_dataHome;
+	std::string	m_cacheHome;
+	std::string	m_runtimeDir;
+	List		m_configDirs;
+	List		m_dataDirs;
+
+public:
+	/**
+	 * Open an xdg instance and load directories.
+	 *
+	 * @throw std::runtime_error on failures
+	 */
+	Xdg();
+
+	/**
+	 * Get the config directory. ${XDG_CONFIG_HOME} or ${HOME}/.config
+	 *
+	 * @return the config directory
+	 */
+	const std::string &configHome() const noexcept;
+
+	/**
+	 * Get the data directory. ${XDG_DATA_HOME} or ${HOME}/.local/share
+	 *
+	 * @return the data directory
+	 */
+	const std::string &dataHome() const noexcept;
+
+	/**
+	 * Get the cache directory. ${XDG_CACHE_HOME} or ${HOME}/.cache
+	 *
+	 * @return the cache directory
+	 */
+	const std::string &cacheHome() const noexcept;
+
+	/**
+	 * Get the runtime directory. ${XDG_RUNTIME_DIR} must be set,
+	 * if not, it throws an exception.
+	 *
+	 * The XDG standard says that application should handle XDG_RUNTIME_DIR by
+	 * themselves.
+	 *
+	 * @return the runtime directory
+	 * @throw std::runtime_error on error
+	 */
+	const std::string &runtimeDir() const;
+
+	/**
+	 * Get the standard config directories. ${XDG_CONFIG_DIRS} or { "/etc/xdg" }
+	 *
+	 * @return the list of config directories
+	 */
+	const List &configDirs() const noexcept;
+
+	/**
+	 * Get the data directories. ${XDG_DATA_DIRS} or { "/usr/local/share", "/usr/share" }
+	 *
+	 * @return the list of data directories
+	 */
+	const List &dataDirs() const noexcept;
+};
+
+#endif // !_XDG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Zip/ZipArchive.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,295 @@
+/*
+ * ZipArchive.cpp -- wrapper around libzip
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+
+#include "ZipArchive.h"
+
+namespace source {
+
+/* --------------------------------------------------------
+ * Buffer (zip_source_buffer)
+ * -------------------------------------------------------- */
+
+Buffer::Buffer(std::string data)
+	: m_data(std::move(data))
+{
+}
+
+struct zip_source *Buffer::source(struct zip *archive) const
+{
+	auto size = m_data.size();
+	auto data = static_cast<char *>(std::malloc(size));
+
+	if (data == nullptr)
+		throw std::runtime_error(std::strerror(errno));
+
+	std::memcpy(data, m_data.data(), size);
+
+	auto src = zip_source_buffer(archive, data, size, 1);
+
+	if (src == nullptr) {
+		std::free(data);
+		throw std::runtime_error(zip_strerror(archive));
+	}
+
+	return src;
+}
+
+/* --------------------------------------------------------
+ * File (zip_source_file)
+ * -------------------------------------------------------- */
+
+File::File(std::string path, ZipUint64 start, ZipInt64 length)
+	: m_path(std::move(path))
+	, m_start(start)
+	, m_length(length)
+{
+}
+
+struct zip_source *File::source(struct zip *archive) const
+{
+	auto src = zip_source_file(archive, m_path.c_str(), m_start, m_length);
+
+	if (src == nullptr)
+		throw std::runtime_error(zip_strerror(archive));
+
+	return src;
+}
+
+} // !source
+
+/* --------------------------------------------------------
+ * ZipArchive
+ * ------------------------------------------------------- */
+
+ZipArchive::ZipArchive(const std::string &path, ZipFlags flags)
+	: m_handle(nullptr, nullptr)
+{
+	int error;
+	struct zip *archive = zip_open(path.c_str(), flags, &error);
+
+	if (archive == nullptr)
+	{
+		char buf[128]{};
+
+		zip_error_to_str(buf, sizeof (buf), error, errno);
+
+		throw std::runtime_error(buf);
+	}
+
+	m_handle = { archive, zip_close };
+}
+
+void ZipArchive::setFileComment(ZipUint64 index, const std::string &text, ZipFlags flags)
+{
+	auto size = text.size();
+	auto cstr = (size == 0) ? nullptr : text.c_str();
+
+	if (zip_file_set_comment(m_handle.get(), index, cstr, size, flags) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+std::string ZipArchive::getFileComment(ZipUint64 index, ZipFlags flags) const
+{
+	zip_uint32_t length{};
+	auto text = zip_file_get_comment(m_handle.get(), index, &length, flags);
+
+	if (text == nullptr)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return { text, length };
+}
+
+void ZipArchive::setComment(const std::string &comment)
+{
+	if (zip_set_archive_comment(m_handle.get(), comment.c_str(), comment.size()) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+std::string ZipArchive::getComment(ZipFlags flags) const
+{
+	int length{};
+	auto text = zip_get_archive_comment(m_handle.get(), &length, flags);
+
+	if (text == nullptr)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return { text, static_cast<size_t>(length) };
+}
+
+ZipInt64 ZipArchive::find(const std::string &name, ZipFlags flags)
+{
+	auto index = zip_name_locate(m_handle.get(), name.c_str(), flags);
+
+	if (index < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return index;
+}
+
+ZipStat ZipArchive::stat(const std::string &name, ZipFlags flags) const
+{
+	ZipStat st;
+
+	if (zip_stat(m_handle.get(), name.c_str(), flags, &st) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return st;
+}
+
+ZipStat ZipArchive::stat(ZipUint64 index, ZipFlags flags) const
+{
+	ZipStat st;
+
+	if (zip_stat_index(m_handle.get(), index, flags, &st) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return st;
+}
+
+ZipInt64 ZipArchive::add(const ZipSource &source, const std::string &name, ZipFlags flags)
+{
+	auto src = source.source(m_handle.get());
+	auto ret = zip_file_add(m_handle.get(), name.c_str(), src, flags);
+
+	if (ret < 0) {
+		zip_source_free(src);
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+	}
+
+	return ret;
+}
+
+ZipInt64 ZipArchive::addDirectory(const std::string &directory, ZipFlags flags)
+{
+	auto ret = zip_dir_add(m_handle.get(), directory.c_str(), flags);
+
+	if (ret < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return ret;
+}
+
+void ZipArchive::replace(const ZipSource &source, ZipUint64 index, ZipFlags flags)
+{
+	auto src = source.source(m_handle.get());
+
+	if (zip_file_replace(m_handle.get(), index, src, flags) < 0) {
+		zip_source_free(src);
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+	}
+}
+
+ZipFile ZipArchive::open(const std::string &name, ZipFlags flags, const std::string &password)
+{
+	struct zip_file *file;
+
+	if (password.size() > 0)
+		file = zip_fopen_encrypted(m_handle.get(), name.c_str(), flags, password.c_str());
+	else
+		file = zip_fopen(m_handle.get(), name.c_str(), flags);
+
+	if (file == nullptr)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return file;
+}
+
+ZipFile ZipArchive::open(ZipUint64 index, ZipFlags flags, const std::string &password)
+{
+	struct zip_file *file;
+
+	if (password.size() > 0)
+		file = zip_fopen_index_encrypted(m_handle.get(), index, flags, password.c_str());
+	else
+		file = zip_fopen_index(m_handle.get(), index, flags);
+
+	if (file == nullptr)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return file;
+}
+
+void ZipArchive::rename(ZipUint64 index, const std::string &name, ZipFlags flags)
+{
+	if (zip_file_rename(m_handle.get(), index, name.c_str(), flags) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+void ZipArchive::setFileCompression(ZipUint64 index, ZipInt32 comp, ZipUint32 flags)
+{
+	if (zip_set_file_compression(m_handle.get(), index, comp, flags) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+void ZipArchive::remove(ZipUint64 index)
+{
+	if (zip_delete(m_handle.get(), index) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+ZipInt64 ZipArchive::numEntries(ZipFlags flags) const noexcept
+{
+	return zip_get_num_entries(m_handle.get(), flags);
+}
+
+void ZipArchive::unchange(ZipUint64 index)
+{
+	if (zip_unchange(m_handle.get(), index) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+void ZipArchive::unchangeAll()
+{
+	if (zip_unchange_all(m_handle.get()) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+void ZipArchive::unchangeArchive()
+{
+	if (zip_unchange_archive(m_handle.get()) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+void ZipArchive::setDefaultPassword(const std::string &password)
+{
+	auto cstr = (password.size() > 0) ? password.c_str() : nullptr;
+
+	if (zip_set_default_password(m_handle.get(), cstr) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+void ZipArchive::setFlag(ZipFlags flags, int value)
+{
+	if (zip_set_archive_flag(m_handle.get(), flags, value) < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+}
+
+int ZipArchive::getFlag(ZipFlags which, ZipFlags flags) const
+{
+	auto ret = zip_get_archive_flag(m_handle.get(), which, flags);
+
+	if (ret < 0)
+		throw std::runtime_error(zip_strerror(m_handle.get()));
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Zip/ZipArchive.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,727 @@
+/*
+ * ZipArchive.h -- wrapper around libzip
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ZIP_ARCHIVE_H_
+#define _ZIP_ARCHIVE_H_
+
+#include <iterator>
+#include <memory>
+#include <string>
+
+#include <zip.h>
+
+using ZipStat = struct zip_stat;
+using ZipSourceCommand = enum zip_source_cmd;
+using ZipCallback = zip_source_callback;
+
+using ZipFlags	= zip_flags_t;
+using ZipInt8	= zip_int8_t;
+using ZipUint8	= zip_uint8_t;
+using ZipInt16	= zip_int16_t;
+using ZipUint16	= zip_uint16_t;
+using ZipInt32	= zip_int32_t;
+using ZipUint32	= zip_uint32_t;
+using ZipInt64	= zip_int64_t;
+using ZipUint64	= zip_uint64_t;
+
+/**
+ * @class ZipSource
+ * @brief Source for adding file
+ */
+class ZipSource {
+public:
+	/**
+	 * Default constructor.
+	 */
+	ZipSource() = default;
+
+	/**
+	 * Virtual destructor.
+	 */
+	virtual ~ZipSource() = default;
+
+	/**
+	 * Create a zip_source structure. Must not be null, throw an exception
+	 * instead.
+	 *
+	 * @return a zip_source ready to be used
+	 * @throw std::runtime_error on errors
+	 * @post must not return null
+	 */
+	virtual struct zip_source *source(struct zip *zip) const = 0;
+};
+
+/**
+ * @class ZipFile
+ * @brief File for reading
+ */
+class ZipFile {
+private:
+	std::unique_ptr<struct zip_file, int (*)(struct zip_file *)> m_handle;
+
+	ZipFile(const ZipFile &) = delete;
+	ZipFile &operator=(const ZipFile &) = delete;
+
+public:
+	/**
+	 * Create a ZipFile with a zip_file structure.
+	 *
+	 * @param file the file ready to be used
+	 */
+	inline ZipFile(struct zip_file *file)
+		: m_handle(file, zip_fclose)
+	{
+	}
+
+	/**
+	 * Move constructor defaulted.
+	 *
+	 * @param other the other ZipFile
+	 */
+	ZipFile(ZipFile &&other) noexcept = default;
+
+	/**
+	 * Move operator defaulted.
+	 *
+	 * @param other the other ZipFile
+	 * @return *this
+	 */
+	ZipFile &operator=(ZipFile &&) noexcept = default;
+
+	/**
+	 * Read some data.
+	 *
+	 * @param data the destination buffer
+	 * @param length the length
+	 * @return the number of bytes written or -1 on failure
+	 */
+	inline int read(void *data, ZipUint64 length) noexcept
+	{
+		return zip_fread(m_handle.get(), data, length);
+	}
+
+	/**
+	 * Read some data to a fixed size array.
+	 *
+	 * @param data the array
+	 * @return the number of bytes written or -1 on failure
+	 */
+	template <size_t Size>
+	inline int read(char (&data)[Size]) noexcept
+	{
+		return read(data, Size);
+	}
+
+	/**
+	 * Optimized function for reading all characters with only one allocation.
+	 * Ideal for combining with ZipArchive::stat.
+	 *
+	 * @param length the length of the file
+	 * @return the whole string
+	 * @see ZipArchive::stat
+	 */
+	std::string read(unsigned length)
+	{
+		std::string result;
+
+		result.resize(length);
+		auto count = read(&result[0], length);
+
+		if (count < 0)
+			return "";
+
+		result.resize(count);
+
+		return result;
+	}
+};
+
+namespace source {
+
+/**
+ * @class Buffer
+ * @brief Create a source from a buffer
+ */
+class Buffer : public ZipSource {
+private:
+	std::string m_data;
+
+public:
+	/**
+	 * Buffer constructor. Moves the data.
+	 *
+	 * @param data the data
+	 */
+	Buffer(std::string data);
+
+	/**
+	 * @copydoc ZipSource::source
+	 */
+	struct zip_source *source(struct zip *archive) const override;
+};
+
+/**
+ * @class File
+ * @brief Create a source from a file on the disk
+ */
+class File : public ZipSource {
+private:
+	std::string m_path;
+	ZipUint64 m_start;
+	ZipInt64 m_length;
+
+public:
+	/**
+	 * File constructor.
+	 *
+	 * @param path the path to the file
+	 * @param start the beginning in the file
+	 * @param length the maximum length
+	 */
+	File(std::string path, ZipUint64 start = 0, ZipInt64 length = -1);
+
+	/**
+	 * @copydoc ZipSource::source
+	 */
+	struct zip_source *source(struct zip *archive) const override;
+};
+
+} // !source
+
+/**
+ * @class ZipStatPtr
+ * @brief Wrapper for ZipStat as pointer
+ */
+class ZipStatPtr {
+private:
+	ZipStat &m_stat;
+
+public:
+	/**
+	 * Constructor.
+	 *
+	 * @param stat the file stat
+	 */
+	inline ZipStatPtr(ZipStat stat) noexcept
+		: m_stat(stat)
+	{
+	}
+
+	/**
+	 * Get the reference.
+	 *
+	 * @return the reference
+	 */
+	inline ZipStat &operator*() const noexcept
+	{
+		return m_stat;
+	}
+
+	/**
+	 * Access the object.
+	 *
+	 * @return the pointer
+	 */
+	inline ZipStat *operator->() const noexcept
+	{
+		return &m_stat;
+	}
+};
+
+/**
+ * @class ZipArchive
+ * @brief Safe wrapper on the struct zip structure
+ */
+class ZipArchive {
+private:
+	using Handle = std::unique_ptr<struct zip, int (*)(struct zip *)>;
+
+	Handle m_handle;
+
+	ZipArchive(const ZipArchive &) = delete;
+	ZipArchive &operator=(const ZipArchive &) = delete;
+
+public:
+	using value_type = ZipStat;
+	using reference = ZipStat;
+	using const_refernce = ZipStat;
+	using pointer = ZipStatPtr;
+	using size_type = unsigned;
+
+	/**
+	 * @class iterator
+	 * @brief Iterator
+	 */
+	class iterator : public std::iterator<std::random_access_iterator_tag, ZipArchive> {
+	private:
+		ZipArchive &m_archive;
+		ZipUint64 m_index;
+
+	public:
+		explicit inline iterator(ZipArchive &archive, ZipUint64 index = 0) noexcept
+			: m_archive(archive)
+			, m_index(index)
+		{
+		}
+
+		inline ZipStat operator*() const
+		{
+			return m_archive.stat(m_index);
+		}
+
+		inline ZipStatPtr operator->() const
+		{
+			return ZipStatPtr(m_archive.stat(m_index));
+		}
+
+		inline iterator &operator++() noexcept
+		{
+			++ m_index;
+
+			return *this;
+		}
+
+		inline iterator operator++(int) noexcept
+		{
+			iterator save = *this;
+
+			++ m_index;
+
+			return save;
+		}
+
+		inline iterator &operator--() noexcept
+		{
+			-- m_index;
+
+			return *this;
+		}
+
+		inline iterator operator--(int) noexcept
+		{
+			iterator save = *this;
+
+			-- m_index;
+
+			return save;
+		}
+
+		inline iterator operator+(int inc) const noexcept
+		{
+			return iterator(m_archive, m_index + inc);
+		}
+
+		inline iterator operator-(int dec) const noexcept
+		{
+			return iterator(m_archive, m_index - dec);
+		}
+
+		inline bool operator==(const iterator &other) const noexcept
+		{
+			return m_index == other.m_index;
+		}
+
+		inline bool operator!=(const iterator &other) const noexcept
+		{
+			return m_index != other.m_index;
+		}
+
+		inline ZipStat operator[](int index) const
+		{
+			return m_archive.stat(index);
+		}
+	};
+
+	/**
+	 * @class const_iterator
+	 * @brief Const iterator
+	 */
+	class const_iterator : public std::iterator<std::random_access_iterator_tag, ZipArchive> {
+	private:
+		const ZipArchive &m_archive;
+		ZipUint64 m_index;
+
+	public:
+		explicit inline const_iterator(const ZipArchive &archive, ZipUint64 index = 0) noexcept
+			: m_archive(archive)
+			, m_index(index)
+		{
+		}
+
+		inline ZipStat operator*() const
+		{
+			return m_archive.stat(m_index);
+		}
+
+		inline ZipStatPtr operator->() const
+		{
+			return ZipStatPtr(m_archive.stat(m_index));
+		}
+
+		inline const_iterator &operator++() noexcept
+		{
+			++ m_index;
+
+			return *this;
+		}
+
+		inline const_iterator operator++(int) noexcept
+		{
+			const_iterator save = *this;
+
+			++ m_index;
+
+			return save;
+		}
+
+		inline const_iterator &operator--() noexcept
+		{
+			-- m_index;
+
+			return *this;
+		}
+
+		inline const_iterator operator--(int) noexcept
+		{
+			const_iterator save = *this;
+
+			-- m_index;
+
+			return save;
+		}
+
+		inline const_iterator operator+(int inc) const noexcept
+		{
+			return const_iterator(m_archive, m_index + inc);
+		}
+
+		inline const_iterator operator-(int dec) const noexcept
+		{
+			return const_iterator(m_archive, m_index - dec);
+		}
+
+		inline bool operator==(const const_iterator &other) const noexcept
+		{
+			return m_index == other.m_index;
+		}
+
+		inline bool operator!=(const const_iterator &other) const noexcept
+		{
+			return m_index != other.m_index;
+		}
+
+		inline ZipStat operator[](int index) const
+		{
+			return m_archive.stat(index);
+		}
+	};
+
+public:
+	/**
+	 * Open an archive on the disk.
+	 *
+	 * @param path the path
+	 * @param flags the optional flags
+	 * @throw std::runtime_error on errors
+	 */
+	ZipArchive(const std::string &path, ZipFlags flags = 0);
+
+	/**
+	 * Move constructor defaulted.
+	 *
+	 * @param other the other ZipArchive
+	 */
+	ZipArchive(ZipArchive &&other) noexcept = default;
+
+	/**
+	 * Move operator defaulted.
+	 *
+	 * @param other the other ZipArchive
+	 * @return *this
+	 */
+	ZipArchive &operator=(ZipArchive &&other) noexcept = default;
+
+	/**
+	 * Get an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline iterator begin() noexcept
+	{
+		return iterator(*this);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator begin() const noexcept
+	{
+		return const_iterator(*this);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator cbegin() const noexcept
+	{
+		return const_iterator(*this);
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline iterator end() noexcept
+	{
+		return iterator(*this, numEntries());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator end() const noexcept
+	{
+		return const_iterator(*this, numEntries());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline const_iterator cend() const noexcept
+	{
+		return const_iterator(*this, numEntries());
+	}
+
+	/**
+	 * Set a comment on a file.
+	 *
+	 * @param index the file index in the archive
+	 * @param text the text or empty to remove the comment
+	 * @param flags the optional flags
+	 * @throw std::runtime_error on errors
+	 */
+	void setFileComment(ZipUint64 index, const std::string &text = "", ZipFlags flags = 0);
+
+	/**
+	 * Get a comment from a file.
+	 *
+	 * @param index the file index in the archive
+	 * @param flags the optional flags
+	 * @return the comment
+	 * @throw std::runtime_error on errors
+	 */
+	std::string getFileComment(ZipUint64 index, ZipFlags flags = 0) const;
+
+	/**
+	 * Set the archive comment.
+	 *
+	 * @param comment the comment
+	 * @throw std::runtime_error on errors
+	 */
+	void setComment(const std::string &comment);
+
+	/**
+	 * Get the archive comment.
+	 *
+	 * @param flags the optional flags
+	 * @return the comment
+	 * @throw std::runtime_error on errors
+	 */
+	std::string getComment(ZipFlags flags = 0) const;
+
+	/**
+	 * Locate a file on the archive.
+	 *
+	 * @param name the name
+	 * @param flags the optional flags
+	 * @return the index
+	 * @throw std::runtime_error on errors
+	 */
+	ZipInt64 find(const std::string &name, ZipFlags flags = 0);
+
+	/**
+	 * Get information about a file.
+	 *
+	 * @param name the name
+	 * @param flags the optional flags
+	 * @return the structure
+	 * @throw std::runtime_error on errors
+	 */
+	ZipStat stat(const std::string &name, ZipFlags flags = 0) const;
+
+	/**
+	 * Get information about a file. Overloaded function.
+	 *
+	 * @param index the file index in the archive
+	 * @param flags the optional flags
+	 * @return the structure
+	 * @throw std::runtime_error on errors
+	 */
+	ZipStat stat(ZipUint64 index, ZipFlags flags = 0) const;
+
+	/**
+	 * Add a file to the archive.
+	 *
+	 * @param source the source
+	 * @param name the name entry in the archive
+	 * @param flags the optional flags
+	 * @return the new index in the archive
+	 * @throw std::runtime_error on errors
+	 * @see source::File
+	 * @see source::Buffer
+	 */
+	ZipInt64 add(const ZipSource &source, const std::string &name, ZipFlags flags = 0);
+
+	/**
+	 * Add a directory to the archive. Not a directory from the disk.
+	 *
+	 * @param directory the directory name
+	 * @param flags the optional flags
+	 * @return the new index in the archive
+	 * @throw std::runtime_error on errors
+	 */
+	ZipInt64 addDirectory(const std::string &directory, ZipFlags flags = 0);
+
+	/**
+	 * Replace an existing file in the archive.
+	 *
+	 * @param source the source
+	 * @param index the file index in the archiev
+	 * @param flags the optional flags
+	 * @throw std::runtime_error on errors
+	 */
+	void replace(const ZipSource &source, ZipUint64 index, ZipFlags flags = 0);
+
+	/**
+	 * Open a file in the archive.
+	 *
+	 * @param name the name
+	 * @param flags the optional flags
+	 * @param password the optional password
+	 * @return the opened file
+	 * @throw std::runtime_error on errors
+	 */
+	ZipFile open(const std::string &name, ZipFlags flags = 0, const std::string &password = "");
+
+	/**
+	 * Open a file in the archive. Overloaded function.
+	 *
+	 * @param index the file index in the archive
+	 * @param flags the optional flags
+	 * @param password the optional password
+	 * @return the opened file
+	 * @throw std::runtime_error on errors
+	 */
+	ZipFile open(ZipUint64 index, ZipFlags flags = 0, const std::string &password = "");
+
+	/**
+	 * Rename an existing entry in the archive.
+	 *
+	 * @param index the file index in the archive
+	 * @param name the new name
+	 * @param flags the optional flags
+	 * @throw std::runtime_error on errors
+	 */
+	void rename(ZipUint64 index, const std::string &name, ZipFlags flags = 0);
+
+	/**
+	 * Set file compression.
+	 *
+	 * @param index the file index in the archive
+	 * @param comp the compression
+	 * @param flags the optional flags
+	 * @throw std::runtime_error on errors
+	 */
+	void setFileCompression(ZipUint64 index, ZipInt32 comp, ZipUint32 flags = 0);
+
+	/**
+	 * Delete a file from the archive.
+	 *
+	 * @param index the file index in the archive
+	 * @throw std::runtime_error on errors
+	 */
+	void remove(ZipUint64 index);
+
+	/**
+	 * Get the number of entries in the archive.
+	 *
+	 * @param flags the optional flags
+	 * @return the number of entries
+	 */
+	ZipInt64 numEntries(ZipFlags flags = 0) const noexcept;
+
+	/**
+	 * Revert changes on the file.
+	 *
+	 * @param index the index
+	 * @throw std::runtime_error on errors
+	 */
+	void unchange(ZipUint64 index);
+
+	/**
+	 * Revert all changes.
+	 *
+	 * @throw std::runtime_error on errors
+	 */
+	void unchangeAll();
+
+	/**
+	 * Revert changes to archive.
+	 *
+	 * @throw std::runtime_error on errors
+	 */
+	void unchangeArchive();
+
+	/**
+	 * Set the defaut password.
+	 *
+	 * @param password the password or empty to unset it
+	 * @throw std::runtime_error on errors
+	 */
+	void setDefaultPassword(const std::string &password = "");
+
+	/**
+	 * Set an archive flag.
+	 *
+	 * @param flag the flag to set
+	 * @param value the value
+	 * @throw std::runtime_error on errors
+	 */
+	void setFlag(ZipFlags flag, int value);
+
+	/**
+	 * Get an archive flag.
+	 *
+	 * @param which which flag
+	 * @param flags the optional flags
+	 * @return the value
+	 * @throw std::runtime_error on errors
+	 */
+	int getFlag(ZipFlags which, ZipFlags flags = 0) const;
+};
+
+#endif // !_ZIP_ARCHIVE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Base64/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,184 @@
+/*
+ * main.cpp -- main test file for Base64
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Base64.h>
+
+TEST(Lookup, lookup)
+{
+	ASSERT_EQ('A', Base64::lookup(0b000000));
+	ASSERT_EQ('B', Base64::lookup(0b000001));
+	ASSERT_EQ('C', Base64::lookup(0b000010));
+	ASSERT_EQ('D', Base64::lookup(0b000011));
+	ASSERT_EQ('E', Base64::lookup(0b000100));
+	ASSERT_EQ('F', Base64::lookup(0b000101));
+	ASSERT_EQ('G', Base64::lookup(0b000110));
+	ASSERT_EQ('H', Base64::lookup(0b000111));
+	ASSERT_EQ('I', Base64::lookup(0b001000));
+	ASSERT_EQ('J', Base64::lookup(0b001001));
+	ASSERT_EQ('K', Base64::lookup(0b001010));
+	ASSERT_EQ('L', Base64::lookup(0b001011));
+	ASSERT_EQ('M', Base64::lookup(0b001100));
+	ASSERT_EQ('N', Base64::lookup(0b001101));
+	ASSERT_EQ('O', Base64::lookup(0b001110));
+	ASSERT_EQ('P', Base64::lookup(0b001111));
+	ASSERT_EQ('Q', Base64::lookup(0b010000));
+	ASSERT_EQ('R', Base64::lookup(0b010001));
+	ASSERT_EQ('S', Base64::lookup(0b010010));
+	ASSERT_EQ('T', Base64::lookup(0b010011));
+	ASSERT_EQ('U', Base64::lookup(0b010100));
+	ASSERT_EQ('V', Base64::lookup(0b010101));
+	ASSERT_EQ('W', Base64::lookup(0b010110));
+	ASSERT_EQ('X', Base64::lookup(0b010111));
+	ASSERT_EQ('Y', Base64::lookup(0b011000));
+	ASSERT_EQ('Z', Base64::lookup(0b011001));
+	ASSERT_EQ('a', Base64::lookup(0b011010));
+	ASSERT_EQ('b', Base64::lookup(0b011011));
+	ASSERT_EQ('c', Base64::lookup(0b011100));
+	ASSERT_EQ('d', Base64::lookup(0b011101));
+	ASSERT_EQ('e', Base64::lookup(0b011110));
+	ASSERT_EQ('f', Base64::lookup(0b011111));
+	ASSERT_EQ('g', Base64::lookup(0b100000));
+	ASSERT_EQ('h', Base64::lookup(0b100001));
+	ASSERT_EQ('i', Base64::lookup(0b100010));
+	ASSERT_EQ('j', Base64::lookup(0b100011));
+	ASSERT_EQ('k', Base64::lookup(0b100100));
+	ASSERT_EQ('l', Base64::lookup(0b100101));
+	ASSERT_EQ('m', Base64::lookup(0b100110));
+	ASSERT_EQ('n', Base64::lookup(0b100111));
+	ASSERT_EQ('o', Base64::lookup(0b101000));
+	ASSERT_EQ('p', Base64::lookup(0b101001));
+	ASSERT_EQ('q', Base64::lookup(0b101010));
+	ASSERT_EQ('r', Base64::lookup(0b101011));
+	ASSERT_EQ('s', Base64::lookup(0b101100));
+	ASSERT_EQ('t', Base64::lookup(0b101101));
+	ASSERT_EQ('u', Base64::lookup(0b101110));
+	ASSERT_EQ('v', Base64::lookup(0b101111));
+	ASSERT_EQ('w', Base64::lookup(0b110000));
+	ASSERT_EQ('x', Base64::lookup(0b110001));
+	ASSERT_EQ('y', Base64::lookup(0b110010));
+	ASSERT_EQ('z', Base64::lookup(0b110011));
+	ASSERT_EQ('0', Base64::lookup(0b110100));
+	ASSERT_EQ('1', Base64::lookup(0b110101));
+	ASSERT_EQ('2', Base64::lookup(0b110110));
+	ASSERT_EQ('3', Base64::lookup(0b110111));
+	ASSERT_EQ('4', Base64::lookup(0b111000));
+	ASSERT_EQ('5', Base64::lookup(0b111001));
+	ASSERT_EQ('6', Base64::lookup(0b111010));
+	ASSERT_EQ('7', Base64::lookup(0b111011));
+	ASSERT_EQ('8', Base64::lookup(0b111100));
+	ASSERT_EQ('9', Base64::lookup(0b111101));
+	ASSERT_EQ('+', Base64::lookup(0b111110));
+	ASSERT_EQ('/', Base64::lookup(0b111111));
+}
+
+TEST(Lookup, rlookup)
+{
+	ASSERT_EQ(0b000000, Base64::rlookup('A'));
+	ASSERT_EQ(0b000001, Base64::rlookup('B'));
+	ASSERT_EQ(0b000010, Base64::rlookup('C'));
+	ASSERT_EQ(0b000011, Base64::rlookup('D'));
+	ASSERT_EQ(0b000100, Base64::rlookup('E'));
+	ASSERT_EQ(0b000101, Base64::rlookup('F'));
+	ASSERT_EQ(0b000110, Base64::rlookup('G'));
+	ASSERT_EQ(0b000111, Base64::rlookup('H'));
+	ASSERT_EQ(0b001000, Base64::rlookup('I'));
+	ASSERT_EQ(0b001001, Base64::rlookup('J'));
+	ASSERT_EQ(0b001010, Base64::rlookup('K'));
+	ASSERT_EQ(0b001011, Base64::rlookup('L'));
+	ASSERT_EQ(0b001100, Base64::rlookup('M'));
+	ASSERT_EQ(0b001101, Base64::rlookup('N'));
+	ASSERT_EQ(0b001110, Base64::rlookup('O'));
+	ASSERT_EQ(0b001111, Base64::rlookup('P'));
+	ASSERT_EQ(0b010000, Base64::rlookup('Q'));
+	ASSERT_EQ(0b010001, Base64::rlookup('R'));
+	ASSERT_EQ(0b010010, Base64::rlookup('S'));
+	ASSERT_EQ(0b010011, Base64::rlookup('T'));
+	ASSERT_EQ(0b010100, Base64::rlookup('U'));
+	ASSERT_EQ(0b010101, Base64::rlookup('V'));
+	ASSERT_EQ(0b010110, Base64::rlookup('W'));
+	ASSERT_EQ(0b010111, Base64::rlookup('X'));
+	ASSERT_EQ(0b011000, Base64::rlookup('Y'));
+	ASSERT_EQ(0b011001, Base64::rlookup('Z'));
+	ASSERT_EQ(0b011010, Base64::rlookup('a'));
+	ASSERT_EQ(0b011011, Base64::rlookup('b'));
+	ASSERT_EQ(0b011100, Base64::rlookup('c'));
+	ASSERT_EQ(0b011101, Base64::rlookup('d'));
+	ASSERT_EQ(0b011110, Base64::rlookup('e'));
+	ASSERT_EQ(0b011111, Base64::rlookup('f'));
+	ASSERT_EQ(0b100000, Base64::rlookup('g'));
+	ASSERT_EQ(0b100001, Base64::rlookup('h'));
+	ASSERT_EQ(0b100010, Base64::rlookup('i'));
+	ASSERT_EQ(0b100011, Base64::rlookup('j'));
+	ASSERT_EQ(0b100100, Base64::rlookup('k'));
+	ASSERT_EQ(0b100101, Base64::rlookup('l'));
+	ASSERT_EQ(0b100110, Base64::rlookup('m'));
+	ASSERT_EQ(0b100111, Base64::rlookup('n'));
+	ASSERT_EQ(0b101000, Base64::rlookup('o'));
+	ASSERT_EQ(0b101001, Base64::rlookup('p'));
+	ASSERT_EQ(0b101010, Base64::rlookup('q'));
+	ASSERT_EQ(0b101011, Base64::rlookup('r'));
+	ASSERT_EQ(0b101100, Base64::rlookup('s'));
+	ASSERT_EQ(0b101101, Base64::rlookup('t'));
+	ASSERT_EQ(0b101110, Base64::rlookup('u'));
+	ASSERT_EQ(0b101111, Base64::rlookup('v'));
+	ASSERT_EQ(0b110000, Base64::rlookup('w'));
+	ASSERT_EQ(0b110001, Base64::rlookup('x'));
+	ASSERT_EQ(0b110010, Base64::rlookup('y'));
+	ASSERT_EQ(0b110011, Base64::rlookup('z'));
+	ASSERT_EQ(0b110100, Base64::rlookup('0'));
+	ASSERT_EQ(0b110101, Base64::rlookup('1'));
+	ASSERT_EQ(0b110110, Base64::rlookup('2'));
+	ASSERT_EQ(0b110111, Base64::rlookup('3'));
+	ASSERT_EQ(0b111000, Base64::rlookup('4'));
+	ASSERT_EQ(0b111001, Base64::rlookup('5'));
+	ASSERT_EQ(0b111010, Base64::rlookup('6'));
+	ASSERT_EQ(0b111011, Base64::rlookup('7'));
+	ASSERT_EQ(0b111100, Base64::rlookup('8'));
+	ASSERT_EQ(0b111101, Base64::rlookup('9'));
+	ASSERT_EQ(0b111110, Base64::rlookup('+'));
+	ASSERT_EQ(0b111111, Base64::rlookup('/'));
+}
+
+TEST(Encode, basic)
+{
+	ASSERT_EQ("YQ==", Base64::encode("a"));
+	ASSERT_EQ("YWI=", Base64::encode("ab"));
+	ASSERT_EQ("YWJj", Base64::encode("abc"));
+
+	ASSERT_EQ("aGVsbG8=", Base64::encode("hello"));
+	ASSERT_EQ("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=", Base64::encode("this is a long sentence"));
+}
+
+TEST(Decode, basic)
+{
+	ASSERT_EQ("a", Base64::decode("YQ=="));
+	ASSERT_EQ("ab", Base64::decode("YWI="));
+	ASSERT_EQ("abc", Base64::decode("YWJj"));
+
+	ASSERT_EQ("hello", Base64::decode("aGVsbG8="));
+	ASSERT_EQ("this is a long sentence", Base64::decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U="));
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Directory/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,115 @@
+/*
+ * main.cpp -- test directory
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Directory.h>
+
+TEST(Filter, withDot)
+{
+	try {
+		auto flags = Directory::NotDotDot;
+		Directory directory(".", flags);
+		bool dot(false);
+		bool dotdot(false);
+
+		for (const auto &entry : directory) {
+			if (entry.name == ".")
+				dot = true;
+			if (entry.name == "..")
+				dotdot = true;
+		}
+
+		ASSERT_TRUE(dot);
+		ASSERT_FALSE(dotdot);
+	} catch (const std::runtime_error &error) {
+		FAIL() << "skipping test because: " << error.what();
+	}
+}
+
+TEST(Filter, withDotDot)
+{
+	try {
+		auto flags = Directory::NotDot;
+		Directory directory(".", flags);
+		bool dot(false);
+		bool dotdot(false);
+
+		for (const auto &entry : directory) {
+			if (entry.name == ".")
+				dot = true;
+			if (entry.name == "..")
+				dotdot = true;
+		}
+
+		ASSERT_FALSE(dot);
+		ASSERT_TRUE(dotdot);
+	} catch (const std::runtime_error &error) {
+		FAIL() << "skipping test because: " << error.what();
+	}
+}
+
+TEST(Filter, withBothDots)
+{
+	try {
+		Directory directory(".");
+		bool dot(false);
+		bool dotdot(false);
+
+		for (const auto &entry : directory) {
+			if (entry.name == ".")
+				dot = true;
+			if (entry.name == "..")
+				dotdot = true;
+		}
+
+		ASSERT_TRUE(dot);
+		ASSERT_TRUE(dotdot);
+	} catch (const std::runtime_error &error) {
+		FAIL() << "skipping test because: " << error.what();
+	}
+}
+
+TEST(Filter, withoutDots)
+{
+	try {
+		auto flags = Directory::NotDot | Directory::NotDotDot;
+		Directory directory(".", flags);
+		bool dot(false);
+		bool dotdot(false);
+
+		for (const auto &entry : directory) {
+			if (entry.name == ".")
+				dot = true;
+			if (entry.name == "..")
+				dotdot = true;
+		}
+
+		ASSERT_FALSE(dot);
+		ASSERT_FALSE(dotdot);
+	} catch (const std::runtime_error &error) {
+		FAIL() << "skipping test because: " << error.what();
+	}
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Dynlib/Plugin.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,12 @@
+#include <string>
+
+#include <DynLib.h>
+
+extern "C" {
+
+void DYNLIB_EXPORT initialize(std::string &result)
+{
+	result = "Hello World";
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Dynlib/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,68 @@
+/*
+ * TestDynLib.cpp -- test the dynamic library loader
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <Dynlib.h>
+
+/*
+ * NOTE: the EXTENSION is defined by CMake in the form of a string
+ * literal containing the appropriate extension for the given system.
+ */
+
+using Initialize = void (*)(std::string &s);
+
+TEST(Basic, initialize)
+{
+	try {
+		Dynlib library("./dynlib-plugin" EXTENSION);
+		Initialize init = library.sym<Initialize>("initialize");
+
+		std::string expected("Hello World");
+		std::string result;
+
+		init(result);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::runtime_error &error) {
+		FAIL() << error.what();
+	} catch (const std::out_of_range &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(Basic, absent)
+{
+	try {
+		Dynlib library("./dynlib-plugin" EXTENSION);
+		library.sym<Initialize>("initialize_typo");
+	} catch (const std::out_of_range &error) {
+		return;
+	}
+
+	FAIL() << "Expected a failure but succeed";
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Flags/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,298 @@
+/*
+ * main.cpp -- main test file for Flags
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cstdint>
+
+#include <gtest/gtest.h>
+
+#include <Flags.h>
+
+enum Standard : uint8_t {
+	Fullscreen	= (1 << 0),
+	Audio		= (1 << 1)
+};
+
+enum class Strong : uint8_t {
+	NoLog		= (1 << 0),
+	NoCheck		= (1 << 1)
+};
+
+/* --------------------------------------------------------
+ * Global operators on standard enum
+ * -------------------------------------------------------- */
+
+TEST(OperatorsStandard, opand)
+{
+	Standard s(Fullscreen | Audio);
+
+	ASSERT_EQ(Fullscreen, (s & Fullscreen));
+	ASSERT_EQ(Audio, (s & Audio));
+}
+
+TEST(OperatorsStandard, opor)
+{
+	Standard s(Fullscreen);
+
+	ASSERT_EQ(3, (s | Audio));
+}
+
+TEST(OperatorsStandard, opxor)
+{
+	Standard s(Fullscreen);
+
+	ASSERT_EQ(3, (s ^ Audio));
+}
+
+TEST(OperatorsStandard, opnot)
+{
+	Standard s(Fullscreen);
+
+	ASSERT_EQ(254, ~s);
+}
+
+/* --------------------------------------------------------
+ * Global operators on strong enum
+ * -------------------------------------------------------- */
+
+TEST(OperatorsStrong, opand)
+{
+	Strong s(Strong::NoLog | Strong::NoCheck);
+
+	ASSERT_EQ(Strong::NoLog, (s & Strong::NoLog));
+	ASSERT_EQ(Strong::NoCheck, (s & Strong::NoCheck));
+}
+
+TEST(OperatorsStrong, opor)
+{
+	Strong s(Strong::NoLog);
+
+	ASSERT_EQ(3, static_cast<int>((s | Strong::NoCheck)));
+}
+
+TEST(OperatorsStrong, opxor)
+{
+	Strong s(Strong::NoLog);
+
+	ASSERT_EQ(3, static_cast<int>((s ^ Strong::NoCheck)));
+}
+
+TEST(OperatorsStrong, opnot)
+{
+	Strong s(Strong::NoLog);
+
+	ASSERT_EQ(254, static_cast<int>(~s));
+}
+
+/* --------------------------------------------------------
+ * Flags with standard enums
+ * -------------------------------------------------------- */
+
+TEST(Standard, construct)
+{
+	Flags<Standard> s;
+
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+
+	Flags <Standard> s2(Fullscreen | Audio);
+
+	ASSERT_TRUE(s2);
+	ASSERT_FALSE(!s2);
+	ASSERT_TRUE(s2 & Fullscreen);
+	ASSERT_TRUE(s2 & Audio);
+	ASSERT_TRUE((s2 & Fullscreen) == Fullscreen);
+	ASSERT_TRUE((s2 & Audio) == Audio);
+	ASSERT_TRUE(s2 == (Audio | Fullscreen));
+}
+
+TEST(Standard, addByOne)
+{
+	Flags<Standard> s;
+
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+	ASSERT_TRUE(!(s & Fullscreen));
+	ASSERT_TRUE(!(s & Audio));
+
+	s |= Fullscreen;
+	ASSERT_TRUE(s);
+	ASSERT_FALSE(!s);
+	ASSERT_TRUE(s & Fullscreen);
+	ASSERT_TRUE((s & Fullscreen) == Fullscreen);
+	ASSERT_FALSE(s & Audio);
+	ASSERT_FALSE((s & Audio) == Audio);
+	ASSERT_TRUE(s == Fullscreen);
+
+	s |= Audio;
+	ASSERT_TRUE(s);
+	ASSERT_FALSE(!s);
+	ASSERT_TRUE(s & Fullscreen);
+	ASSERT_TRUE((s & Fullscreen) == Fullscreen);
+	ASSERT_TRUE(s & Audio);
+	ASSERT_TRUE((s & Audio) == Audio);
+	ASSERT_TRUE(s == (Fullscreen | Audio));
+}
+
+TEST(Standard, add)
+{
+	Flags<Standard> s;
+
+	s |= Fullscreen | Audio;
+	ASSERT_TRUE(s & (Fullscreen | Audio));
+	ASSERT_TRUE((s & (Fullscreen | Audio)) == (Fullscreen | Audio));
+}
+
+TEST(Standard, removeByOne)
+{
+	Flags<Standard> s(Fullscreen | Audio);
+
+	s &= ~(Fullscreen);
+	ASSERT_TRUE(s);
+	ASSERT_FALSE(!s);
+	ASSERT_FALSE(s & Fullscreen);
+	ASSERT_FALSE((s & Fullscreen) == Fullscreen);
+	ASSERT_TRUE(s & Audio);
+	ASSERT_TRUE((s & Audio) == Audio);
+
+	s &= ~(Audio);
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+}
+
+TEST(Standard, remove)
+{
+	Flags<Standard> s(Fullscreen | Audio);
+
+	s &= ~(Fullscreen | Audio);
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+}
+
+TEST(Standard, xorAdd)
+{
+	Flags<Standard> s(Fullscreen | Audio);
+
+	s ^= Audio;
+	ASSERT_TRUE(s & Fullscreen);
+	ASSERT_TRUE((s & Fullscreen) == Fullscreen);
+	ASSERT_FALSE(s & Audio);
+	ASSERT_FALSE((s & Audio) == Audio);
+}
+
+/* --------------------------------------------------------
+ * Flags with strong enums
+ * -------------------------------------------------------- */
+
+TEST(Strong, construct)
+{
+	Flags<Strong> s;
+
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+
+	Flags <Strong> s2(Strong::NoLog | Strong::NoCheck);
+
+	ASSERT_TRUE(s2);
+	ASSERT_FALSE(!s2);
+	ASSERT_TRUE(s2 & Strong::NoLog);
+	ASSERT_TRUE(s2 & Strong::NoCheck);
+	ASSERT_TRUE((s2 & Strong::NoLog) == Strong::NoLog);
+	ASSERT_TRUE((s2 & Strong::NoCheck) == Strong::NoCheck);
+	ASSERT_TRUE(s2 == (Strong::NoLog | Strong::NoCheck));
+}
+
+TEST(Strong, addByOne)
+{
+	Flags<Strong> s;
+
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+	ASSERT_TRUE(!(s & Strong::NoLog));
+	ASSERT_TRUE(!(s & Strong::NoCheck));
+
+	s |= Strong::NoLog;
+	ASSERT_TRUE(s);
+	ASSERT_FALSE(!s);
+	ASSERT_TRUE(s & Strong::NoLog);
+	ASSERT_TRUE((s & Strong::NoLog) == Strong::NoLog);
+	ASSERT_FALSE(s & Strong::NoCheck);
+	ASSERT_FALSE((s & Strong::NoCheck) == Strong::NoCheck);
+	ASSERT_TRUE(s == Strong::NoLog);
+
+	s |= Strong::NoCheck;
+	ASSERT_TRUE(s);
+	ASSERT_FALSE(!s);
+	ASSERT_TRUE(s & Strong::NoLog);
+	ASSERT_TRUE((s & Strong::NoLog) == Strong::NoLog);
+	ASSERT_TRUE(s & Strong::NoCheck);
+	ASSERT_TRUE((s & Strong::NoCheck) == Strong::NoCheck);
+	ASSERT_TRUE(s == (Strong::NoLog | Strong::NoCheck));
+}
+
+TEST(Strong, add)
+{
+	Flags<Strong> s;
+
+	s |= Strong::NoLog | Strong::NoCheck;
+	ASSERT_TRUE(s & (Strong::NoLog | Strong::NoCheck));
+	ASSERT_TRUE((s & (Strong::NoLog | Strong::NoCheck)) == (Strong::NoLog | Strong::NoCheck));
+}
+
+TEST(Strong, removeByOne)
+{
+	Flags<Strong> s(Strong::NoLog | Strong::NoCheck);
+
+	s &= ~(Strong::NoLog);
+	ASSERT_TRUE(s);
+	ASSERT_FALSE(!s);
+	ASSERT_FALSE(s & Strong::NoLog);
+	ASSERT_FALSE((s & Strong::NoLog) == Strong::NoLog);
+	ASSERT_TRUE(s & Strong::NoCheck);
+	ASSERT_TRUE((s & Strong::NoCheck) == Strong::NoCheck);
+
+	s &= ~(Strong::NoCheck);
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+}
+
+TEST(Strong, remove)
+{
+	Flags<Strong> s(Strong::NoLog | Strong::NoCheck);
+
+	s &= ~(Strong::NoLog | Strong::NoCheck);
+	ASSERT_FALSE(s);
+	ASSERT_TRUE(!s);
+}
+
+TEST(Strong, xorAdd)
+{
+	Flags<Strong> s(Strong::NoLog | Strong::NoCheck);
+
+	s ^= Strong::NoCheck;
+	ASSERT_TRUE(s & Strong::NoLog);
+	ASSERT_TRUE((s & Strong::NoLog) == Strong::NoLog);
+	ASSERT_FALSE(s & Strong::NoCheck);
+	ASSERT_FALSE((s & Strong::NoCheck) == Strong::NoCheck);
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Hash/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,64 @@
+/*
+ * main.cpp -- test the hash cryptographic functions
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Hash.h>
+
+/*
+ * We test the "Hello World" message in all cryptographic functions.
+ */
+
+TEST(Hash, md5)
+{
+	std::string expected = "b10a8db164e0754105b7a99be72e3fe5";
+	std::string output = Hash::md5("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+TEST(Hash, sha1)
+{
+	std::string expected = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
+	std::string output = Hash::sha1("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+TEST(Hash, sha256)
+{
+	std::string expected = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e";
+	std::string output = Hash::sha256("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+TEST(Hash, sha512)
+{
+	std::string expected = "2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b";
+	std::string output = Hash::sha512("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/compact.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,1 @@
+[general]verbose=true foreground=false[server]host=google.fr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/error-badcomment.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,2 @@
+[general]
+verbose #hello = xyz
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/error-badsection.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,2 @@
+[[general]
+verbose = false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/error-lineassigment.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,4 @@
+[general]
+host
+=
+google.fr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/error-nosection.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,1 @@
+option = value
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/includes.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,5 @@
+# With some includes
+@include "simple.conf"	# comments also work here
+
+[standard]
+verbose = false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/multi.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,7 @@
+[entity]
+name	= "Player"
+version	= 1.0
+
+[entity]
+name	= "Subwinner"
+version	= 2.0
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/novalue.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,6 @@
+[plugins]
+histedit=
+highlight= #empty
+general = 
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/simple.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,4 @@
+[general]
+option1=1
+option2 =2
+option3 = 3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/configs/tokens.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,3 @@
+[tokens]
+bracket = "I have [brackets]"
+at = "I have foo@at"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Ini/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,250 @@
+/*
+ * main.cpp -- main test file for Ini
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <Ini.h>
+
+class BasicTest : public testing::Test {
+protected:
+	Ini m_ini;
+
+public:
+	BasicTest()
+		: m_ini("Ini/simple.conf")
+	{
+	}
+
+};
+
+TEST_F(BasicTest, simple)
+{
+	ASSERT_EQ(1, static_cast<int>(m_ini.size()));
+}
+
+TEST_F(BasicTest, iniOperators)
+{
+	try {
+		ASSERT_EQ(3, static_cast<int>(m_ini[0].size()));
+		ASSERT_EQ("general", m_ini[0].key());
+		ASSERT_EQ("general", m_ini["general"].key());
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST_F(BasicTest, iniSectionOperators)
+{
+	try {
+		// option1=1 (indexes)
+		ASSERT_EQ("option1", m_ini[0][0].key());
+		ASSERT_EQ("1", m_ini[0][0].value());
+
+		// option1=1 (keys)
+		ASSERT_EQ("option1", m_ini["general"]["option1"].key());
+		ASSERT_EQ("1", m_ini["general"]["option1"].value());
+
+		// option2 =2 (indexes)
+		ASSERT_EQ("option2", m_ini[0][1].key());
+		ASSERT_EQ("2", m_ini[0][1].value());
+
+		// option2 =2 (keys)
+		ASSERT_EQ("option2", m_ini["general"]["option2"].key());
+		ASSERT_EQ("2", m_ini["general"]["option2"].value());
+
+		// option3 = 3 (indexes)
+		ASSERT_EQ("option3", m_ini[0][2].key());
+		ASSERT_EQ("3", m_ini[0][2].value());
+
+		// option3 = 3 (keys)
+		ASSERT_EQ("option3", m_ini["general"]["option3"].key());
+		ASSERT_EQ("3", m_ini["general"]["option3"].value());
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Reserved tokens in words
+ * -------------------------------------------------------- */
+
+TEST(Tokens, iniReserved)
+{
+	try {
+		Ini ini("Ini/tokens.conf");
+
+		ASSERT_EQ("I have [brackets]", ini["tokens"]["bracket"].value());
+		ASSERT_EQ("I have foo@at", ini["tokens"]["at"].value());
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Multiple definition
+ * -------------------------------------------------------- */
+
+class MultiTest : public testing::Test {
+protected:
+	Ini m_ini;
+
+public:
+	MultiTest()
+		: m_ini("Ini/multi.conf")
+	{
+	}
+};
+
+TEST_F(MultiTest, defined)
+{
+	ASSERT_EQ(2, static_cast<int>(m_ini.size()));
+	ASSERT_EQ("name", m_ini[0]["name"].key());
+	ASSERT_EQ("Player", m_ini[0]["name"].value());
+	ASSERT_EQ("version", m_ini[0]["version"].key());
+	ASSERT_EQ("1.0", m_ini[0]["version"].value());
+	ASSERT_EQ("name", m_ini[1]["name"].key());
+	ASSERT_EQ("Subwinner", m_ini[1]["name"].value());
+	ASSERT_EQ("version", m_ini[1]["version"].key());
+	ASSERT_EQ("2.0", m_ini[1]["version"].value());
+}
+
+/* --------------------------------------------------------
+ * Option with no values
+ * -------------------------------------------------------- */
+
+class NoValueTest : public testing::Test {
+protected:
+	Ini m_ini;
+
+public:
+	NoValueTest()
+		: m_ini("Ini/novalue.conf")
+	{
+	}
+};
+
+TEST_F(NoValueTest, isDefined)
+{
+	ASSERT_EQ("plugins", m_ini[0].key());
+	ASSERT_EQ("", m_ini["plugins"]["histedit"].value());
+	ASSERT_EQ("", m_ini["plugins"]["highlight"].value());
+	ASSERT_EQ("", m_ini["plugins"]["general"].value());
+}
+
+/* --------------------------------------------------------
+ * Include tests
+ * -------------------------------------------------------- */
+
+class IncludeTest : public testing::Test {
+protected:
+	Ini m_ini;
+
+public:
+	IncludeTest()
+		: m_ini("Ini/includes.conf")
+	{
+	}
+};
+
+TEST_F(IncludeTest, all)
+{
+	ASSERT_EQ(2, static_cast<int>(m_ini.size()));
+
+	// from include
+	ASSERT_EQ("1", m_ini[0][0].value());
+	ASSERT_EQ("2", m_ini[0][1].value());
+	ASSERT_EQ("3", m_ini[0][2].value());
+
+	// from standard
+	ASSERT_EQ("false", m_ini[1][0].value());
+}
+
+/* --------------------------------------------------------
+ * Compact
+ * -------------------------------------------------------- */
+
+TEST(Compact, test)
+{
+	try {
+		Ini ini("Ini/compact.conf");
+
+		ASSERT_EQ(2, static_cast<int>(ini.size()));
+		ASSERT_EQ("true", ini["general"]["verbose"].value());
+		ASSERT_EQ("false", ini["general"]["foreground"].value());
+		ASSERT_EQ("google.fr", ini["server"]["host"].value());
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Errors
+ * -------------------------------------------------------- */
+
+TEST(Errors, nosection)
+{
+	// An option outside a section is not allowed
+	try {
+		Ini ini("Ini/error-nosection.conf");
+
+		FAIL() << "Failure expected, got success";
+	} catch (const std::exception &ex) {
+	}
+}
+
+TEST(Errors, lineassigment)
+{
+	// The = assignment must be on the same line as the option key
+	try {
+		Ini ini("Ini/error-lineassigment.conf");
+
+		FAIL() << "Failure expected, got success";
+	} catch (const std::exception &ex) {
+	}
+}
+
+TEST(Errors, badcomment)
+{
+	// Comment can't between option-key and = assigment
+	try {
+		Ini ini("Ini/error-badcomment.conf");
+
+		FAIL() << "Failure expected, got success";
+	} catch (const std::exception &ex) {
+	}
+}
+
+TEST(Errors, badsection)
+{
+	// Bad section naming
+	try {
+		Ini ini("Ini/error-badsection.conf");
+
+		FAIL() << "Failure expected, got success";
+	} catch (const std::exception &ex) {
+	}
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Json/data/array-all.json	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,9 @@
+[
+    123,
+    9.2,
+    false,
+    true,
+    null,
+    {},
+    []
+]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Json/data/array.json	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,1 @@
+[1, 2, 3]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Json/data/object-all.json	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,9 @@
+{
+    "integer": 123,
+    "real": 9.2,
+    "false": false,
+    "true": true,
+    "null": null,
+    "object": {},
+    "array": []
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Json/data/object.json	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "simple",
+    "description": "basic JSON file"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Json/data/simple.json	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,2 @@
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Json/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,877 @@
+/*
+ * main.cpp -- test the jansson wrapper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <set>
+#include <unordered_map>
+
+#include <gtest/gtest.h>
+
+#include "Json.h"
+
+/* --------------------------------------------------------
+ * Miscellaneous
+ * -------------------------------------------------------- */
+
+TEST(Misc, copy)
+{
+	JsonObject object;
+
+	object.set("integer", 123);
+	object.set("true", true);
+
+	JsonObject object2{object};
+
+	ASSERT_TRUE(object2.isObject());
+	ASSERT_EQ(123, object2["integer"].toInteger());
+	ASSERT_TRUE(object2["true"].isTrue());
+}
+
+TEST(Misc, copyAssign)
+{
+	JsonObject object;
+
+	{
+		JsonObject tmp;
+
+		tmp.set("integer", 123);
+		tmp.set("true", true);
+
+		object = tmp;
+	}
+
+	ASSERT_TRUE(object.isObject());
+	ASSERT_EQ(123, object["integer"].toInteger());
+	ASSERT_TRUE(object["true"].isTrue());
+}
+
+TEST(Misc, move)
+{
+	JsonObject object(123);
+	JsonObject object2(std::move(object));
+
+	ASSERT_TRUE(object.isNull());
+	ASSERT_TRUE(object2.isInteger());
+	ASSERT_EQ(123, object2.toInteger());
+}
+
+TEST(Misc, moveAssign)
+{
+	JsonObject object(123);
+	JsonObject object2;
+
+	object2 = std::move(object);
+
+	ASSERT_TRUE(object.isNull());
+	ASSERT_TRUE(object2.isInteger());
+	ASSERT_EQ(123, object2.toInteger());
+}
+
+/* --------------------------------------------------------
+ * JsonValue constructors
+ * -------------------------------------------------------- */
+
+TEST(Constructors, null)
+{
+	try {
+		JsonValue value;
+
+		ASSERT_TRUE(value.isNull());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Constructors, boolean)
+{
+	try {
+		JsonValue value{true};
+
+		ASSERT_TRUE(value.isTrue());
+		ASSERT_TRUE(value.isBoolean());
+		ASSERT_FALSE(value.isFalse());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Constructors, integer)
+{
+	try {
+		JsonValue value{123};
+
+		ASSERT_TRUE(value.isInteger());
+		ASSERT_TRUE(value.isNumber());
+		ASSERT_FALSE(value.isReal());
+		ASSERT_EQ(123, value.toInteger());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Constructors, real)
+{
+	try {
+		JsonValue value{9.2};
+
+		ASSERT_TRUE(value.isReal());
+		ASSERT_TRUE(value.isNumber());
+		ASSERT_FALSE(value.isInteger());
+		ASSERT_EQ(9.2, value.toReal());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Constructors, string)
+{
+	try {
+		JsonValue value("hello");
+
+		ASSERT_TRUE(value.isString());
+		ASSERT_EQ("hello", value.toString());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Object
+ * -------------------------------------------------------- */
+
+TEST(Object, set)
+{
+	try {
+		JsonObject object;
+
+		object.set("integer", 123);
+		object.set("string", "hello");
+		object.set("true", true);
+
+		ASSERT_EQ(123, object["integer"].toInteger());
+		ASSERT_EQ("hello", object["string"].toString());
+		ASSERT_TRUE(object["true"].isTrue());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Object, clear)
+{
+	try {
+		JsonObject object;
+
+		object.set("integer", 123);
+		object.set("string", "hello");
+		object.set("true", true);
+
+		object.clear();
+
+		ASSERT_EQ(0, static_cast<int>(object.size()));
+		ASSERT_FALSE(object.contains("integer"));
+		ASSERT_FALSE(object.contains("string"));
+		ASSERT_FALSE(object.contains("true"));
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Object, erase)
+{
+	try {
+		JsonObject object;
+
+		object.set("integer", 123);
+		object.set("string", "hello");
+		object.set("true", true);
+
+		object.erase("integer");
+
+		ASSERT_EQ(2, static_cast<int>(object.size()));
+		ASSERT_FALSE(object.contains("integer"));
+		ASSERT_TRUE(object.contains("string"));
+		ASSERT_TRUE(object.contains("true"));
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(ObjectInitializer, simple)
+{
+	try {
+		JsonObject object{
+			{ "username", "jean" },
+			{ "age", 99 }
+		};
+
+		ASSERT_EQ(2, static_cast<int>(object.size()));
+		ASSERT_EQ("jean", object["username"].toString());
+		ASSERT_EQ(99, object["age"].toInteger());
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(ObjectInitializer, deep)
+{
+	try {
+		JsonObject object{
+			{ "username", "jean"		},
+			{ "age", 99			},
+			{ "network", JsonObject{
+					{ "port", 9999 		},
+					{ "host", "localhost"	}
+				}
+			}
+		};
+
+		// First
+		ASSERT_EQ(3, static_cast<int>(object.size()));
+		ASSERT_EQ("jean", object["username"].toString());
+		ASSERT_EQ(99, object["age"].toInteger());
+
+		// Second
+		JsonObject network = object["network"].toObject();
+		ASSERT_TRUE(network.isObject());
+		ASSERT_EQ(2, static_cast<int>(network.size()));
+		ASSERT_EQ(9999, network["port"].toInteger());
+		ASSERT_EQ("localhost", network["host"].toString());
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Array
+ * -------------------------------------------------------- */
+
+TEST(Array, push)
+{
+	try {
+		JsonArray array;
+
+		ASSERT_TRUE(array.isArray());
+
+		array.push(1);
+		array.push("hello");
+		array.push(true);
+
+		ASSERT_EQ(3, static_cast<int>(array.size()));
+		ASSERT_TRUE(array[0].isTrue());
+		ASSERT_EQ("hello", array[1].toString());
+		ASSERT_EQ(1, array[2].toInteger());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Array, append)
+{
+	try {
+		JsonArray array;
+
+		ASSERT_TRUE(array.isArray());
+
+		array.append(1);
+		array.append("hello");
+		array.append(true);
+
+		ASSERT_EQ(3, static_cast<int>(array.size()));
+		ASSERT_EQ(1, array[0].toInteger());
+		ASSERT_EQ("hello", array[1].toString());
+		ASSERT_TRUE(array[2].isTrue());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Array, insert)
+{
+	try {
+		JsonArray array;
+
+		ASSERT_TRUE(array.isArray());
+
+		array.insert(1, 0);
+		array.insert("hello", 1);
+		array.insert(true, 0);
+
+		ASSERT_EQ(3, static_cast<int>(array.size()));
+		ASSERT_TRUE(array[0].isTrue());
+		ASSERT_EQ(1, array[1].toInteger());
+		ASSERT_EQ("hello", array[2].toString());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Array, clear)
+{
+	try {
+		JsonArray array;
+
+		array.append(1);
+		array.append("hello");
+		array.append(true);
+
+		array.clear();
+
+		ASSERT_EQ(0, static_cast<int>(array.size()));
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Array, erase)
+{
+	try {
+		JsonArray array;
+
+		array.append(1);
+		array.append("hello");
+		array.append(true);
+
+		array.erase(0);
+
+		ASSERT_EQ(2, static_cast<int>(array.size()));
+		ASSERT_EQ("hello", array[0].toString());
+		ASSERT_TRUE(array[1].isTrue());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Array, eraseIterator)
+{
+	try {
+		JsonArray array;
+
+		array.append(1);
+		array.append("hello");
+		array.append(true);
+
+		array.erase(array.begin());
+
+		ASSERT_EQ(2, static_cast<int>(array.size()));
+		ASSERT_EQ("hello", array[0].toString());
+		ASSERT_TRUE(array[1].isTrue());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Array, eraseConstIterator)
+{
+	try {
+		JsonArray array;
+
+		array.append(1);
+		array.append("hello");
+		array.append(true);
+
+		array.erase(array.cbegin());
+
+		ASSERT_EQ(2, static_cast<int>(array.size()));
+		ASSERT_EQ("hello", array[0].toString());
+		ASSERT_TRUE(array[1].isTrue());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(ArrayInitializer, simple)
+{
+	try {
+		JsonArray array{123, true, "hello"};
+
+		ASSERT_EQ(3, static_cast<int>(array.size()));
+		ASSERT_EQ(123, array[0].toInteger());
+		ASSERT_TRUE(array[1].isTrue());
+		ASSERT_EQ("hello", array[2].toString());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(ArrayInitializer, deep)
+{
+	try {
+		JsonArray array{
+			123,
+			true,
+			"hello",
+			JsonArray{
+				321,
+				false,
+				"olleh"
+			}
+		};
+
+		// First
+		ASSERT_EQ(4, static_cast<int>(array.size()));
+		ASSERT_EQ(123, array[0].toInteger());
+		ASSERT_TRUE(array[1].isTrue());
+		ASSERT_EQ("hello", array[2].toString());
+
+		// Second
+		JsonArray array2 = array[3].toArray();
+		ASSERT_TRUE(array.isArray());
+		ASSERT_EQ(3, static_cast<int>(array2.size()));
+		ASSERT_EQ(321, array2[0].toInteger());
+		ASSERT_TRUE(array2[1].isFalse());
+		ASSERT_EQ("olleh", array2[2].toString());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * I/O
+ * -------------------------------------------------------- */
+
+TEST(FileRead, simple)
+{
+	try {
+		JsonDocument doc(std::ifstream("Json/simple.json"));
+
+		ASSERT_TRUE(doc.isObject());
+		ASSERT_FALSE(doc.isArray());
+
+		JsonObject object = doc.toObject();
+		JsonArray array = doc.toArray();
+
+		ASSERT_TRUE(object.isObject());
+		ASSERT_FALSE(array.isArray());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(FileRead, fail)
+{
+	try {
+		JsonDocument(std::ifstream("Json/notexist.json"));
+
+		FAIL() << "Exception expected";
+	} catch (const JsonError &) {
+	}
+}
+
+TEST(FileWrite, simple)
+{
+	try {
+		JsonObject object{
+			{ "name", "jean" },
+			{ "age", 99 }
+		};
+
+		object.write(std::ofstream("object-write.json"));
+
+		JsonObject object2 = JsonDocument(std::ifstream("object-write.json")).toObject();
+
+		ASSERT_EQ(object2, object);
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(StringRead, simple)
+{
+	try {
+		JsonDocument doc("{ \"license\": \"ISC\" }");
+
+		ASSERT_TRUE(doc.isObject());
+		ASSERT_FALSE(doc.isArray());
+
+		JsonObject object = doc.toObject();
+		JsonArray array = doc.toArray();
+
+		ASSERT_TRUE(object.isObject());
+		ASSERT_FALSE(array.isArray());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(StringRead, fail)
+{
+	try {
+		JsonDocument("{ \"license\": ISC }");
+
+		FAIL() << "Exception expected";
+	} catch (const JsonError &ex) {
+	}
+}
+
+TEST(StringWrite, simple)
+{
+	try {
+		JsonObject object{
+			{ "name", "jean" },
+			{ "age", 99 }
+		};
+
+		JsonObject object2 = JsonDocument(object.dump()).toObject();
+
+		ASSERT_EQ(object2, object);
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Object read
+ * -------------------------------------------------------- */
+
+class ObjectRead : public testing::Test {
+protected:
+	JsonObject m_object;
+	JsonObject m_objectAll;
+
+public:
+	ObjectRead()
+	{
+		m_object = JsonDocument(std::ifstream("Json/object.json")).toObject();
+		m_objectAll = JsonDocument(std::ifstream("Json/object-all.json")).toObject();
+	}
+};
+
+TEST_F(ObjectRead, simple)
+{
+	try {
+		JsonValue name = m_object["name"];
+		JsonValue description = m_object["description"];
+
+		ASSERT_TRUE(name.isString());
+		ASSERT_TRUE(description.isString());
+		ASSERT_EQ("simple", name.toString());
+		ASSERT_EQ("basic JSON file", description.toString());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST_F(ObjectRead, all)
+{
+	try {
+		ASSERT_TRUE(m_objectAll.contains("integer"));
+		ASSERT_FALSE(m_objectAll.contains("unexistant"));
+
+		ASSERT_TRUE(m_objectAll["integer"].isInteger());
+		ASSERT_TRUE(m_objectAll["integer"].isNumber());
+		ASSERT_EQ(123, m_objectAll["integer"].toInteger());
+
+		ASSERT_TRUE(m_objectAll["real"].isReal());
+		ASSERT_TRUE(m_objectAll["real"].isNumber());
+		ASSERT_EQ(9.2, m_objectAll["real"].toReal());
+
+		ASSERT_TRUE(m_objectAll["false"].isBoolean());
+		ASSERT_TRUE(m_objectAll["false"].isFalse());
+		ASSERT_FALSE(m_objectAll["false"].isTrue());
+
+		ASSERT_TRUE(m_objectAll["true"].isBoolean());
+		ASSERT_TRUE(m_objectAll["true"].isTrue());
+		ASSERT_FALSE(m_objectAll["true"].isFalse());
+
+		ASSERT_TRUE(m_objectAll["null"].isNull());
+
+		ASSERT_TRUE(m_objectAll["object"].isObject());
+		ASSERT_TRUE(m_objectAll["array"].isArray());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Array read
+ * -------------------------------------------------------- */
+
+class ArrayRead : public testing::Test {
+protected:
+	JsonArray m_array;
+	JsonArray m_arrayAll;
+
+public:
+	ArrayRead()
+	{
+		m_array = JsonDocument(std::ifstream("Json/array.json")).toArray();
+		m_arrayAll = JsonDocument(std::ifstream("Json/array-all.json")).toArray();
+	}
+};
+
+TEST_F(ArrayRead, simple)
+{
+	try {
+		ASSERT_EQ(3, static_cast<int>(m_array.size()));
+		ASSERT_EQ(1, m_array[0].toInteger());
+		ASSERT_EQ(2, m_array[1].toInteger());
+		ASSERT_EQ(3, m_array[2].toInteger());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST_F(ArrayRead, all)
+{
+	try {
+		ASSERT_TRUE(m_arrayAll[0].isInteger());
+		ASSERT_TRUE(m_arrayAll[0].isNumber());
+		ASSERT_EQ(123, m_arrayAll[0].toInteger());
+
+		ASSERT_TRUE(m_arrayAll[1].isReal());
+		ASSERT_TRUE(m_arrayAll[1].isNumber());
+		ASSERT_EQ(9.2, m_arrayAll[1].toReal());
+
+		ASSERT_TRUE(m_arrayAll[2].isBoolean());
+		ASSERT_TRUE(m_arrayAll[2].isFalse());
+		ASSERT_FALSE(m_arrayAll[2].isTrue());
+
+		ASSERT_TRUE(m_arrayAll[3].isBoolean());
+		ASSERT_TRUE(m_arrayAll[3].isTrue());
+		ASSERT_FALSE(m_arrayAll[3].isFalse());
+
+		ASSERT_TRUE(m_arrayAll[4].isNull());
+
+		ASSERT_TRUE(m_arrayAll[5].isObject());
+		ASSERT_TRUE(m_arrayAll[6].isArray());
+	} catch (const JsonError &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Object iterators
+ * -------------------------------------------------------- */
+
+class ObjectIteratorsTest : public testing::Test {
+protected:
+	JsonObject m_object;
+
+public:
+	ObjectIteratorsTest()
+	{
+		m_object.set("integer", 1);
+		m_object.set("string", "hello");
+		m_object.set("boolean", true);
+	}
+};
+
+TEST_F(ObjectIteratorsTest, operators)
+{
+	// Read only (non const)
+	{
+		std::set<std::string> expected{"boolean", "integer", "string"};
+		std::set<std::string> result;
+		std::unordered_map<std::string, JsonValue> values;
+		JsonObject::iterator it = m_object.begin();
+		JsonObject::iterator end = m_object.end();
+
+		while (it != end) {
+			values.insert({it->first, it->second});
+			result.insert((*it++).first);
+		}
+
+		ASSERT_EQ(expected, result);
+		ASSERT_EQ(1, values["integer"].toInteger());
+		ASSERT_EQ("hello", values["string"].toString());
+		ASSERT_TRUE(values["boolean"].isTrue());
+	}
+
+	// Read only (const)
+	{
+		std::set<std::string> expected{"boolean", "integer", "string"};
+		std::set<std::string> result;
+		std::unordered_map<std::string, JsonValue> values;
+		JsonObject::const_iterator it = m_object.cbegin();
+		JsonObject::const_iterator end = m_object.cend();
+
+		while (it != end) {
+			values.insert({it->first, it->second});
+			result.insert((*it++).first);
+		}
+
+		ASSERT_EQ(expected, result);
+		ASSERT_EQ(1, values["integer"].toInteger());
+		ASSERT_EQ("hello", values["string"].toString());
+		ASSERT_TRUE(values["boolean"].isTrue());
+	}
+}
+
+TEST_F(ObjectIteratorsTest, assign)
+{
+	// Assign (non const)
+	{
+		JsonObject::iterator it = m_object.begin();
+		std::string key = it->first;
+
+		it->second = JsonValue("CHANGED");
+
+		ASSERT_EQ("CHANGED", m_object[key].toString());
+		ASSERT_EQ("CHANGED", it->second.toString());
+		ASSERT_EQ(3, static_cast<int>(m_object.size()));
+	}
+}
+
+TEST_F(ObjectIteratorsTest, assignConst)
+{
+	// Assign (const)
+	{
+		JsonObject::const_iterator it = m_object.cbegin();
+		std::string key = it->first;
+		JsonValue orig = it->second;
+
+		it->second = JsonValue("CHANGED");
+
+		ASSERT_TRUE(m_object.contains(key));
+		ASSERT_EQ(orig, m_object[key]);
+		ASSERT_EQ(3, static_cast<int>(m_object.size()));
+	}
+}
+
+/* --------------------------------------------------------
+ * Array iterators
+ * -------------------------------------------------------- */
+
+class ArrayIteratorsTest : public testing::Test {
+protected:
+	JsonArray m_array;
+
+public:
+	ArrayIteratorsTest()
+	{
+		m_array.append(1);
+		m_array.append("hello");
+		m_array.append(true);
+	}
+};
+
+TEST_F(ArrayIteratorsTest, operators)
+{
+	// Read only (non const)
+	{
+		JsonArray::iterator it = m_array.begin();
+
+		ASSERT_EQ(1, (*it).toInteger());
+		ASSERT_EQ(1, it->toInteger());
+		ASSERT_EQ("hello", it[1].toString());
+		ASSERT_TRUE(it[2].isTrue());
+
+		JsonArray::iterator it2 = it + 1;
+		ASSERT_EQ(1, it2[-1].toInteger());
+		ASSERT_EQ("hello", it2->toString());
+		ASSERT_TRUE(it2[1].isTrue());
+
+		JsonArray::iterator it3 = it;
+		ASSERT_TRUE(it2 != it);
+		ASSERT_FALSE(it3 != it);
+
+		ASSERT_FALSE(it2 == it);
+		ASSERT_TRUE(it3 == it);
+
+		ASSERT_TRUE(it3 >= it);
+		ASSERT_TRUE(it2 >= it);
+
+		ASSERT_TRUE(it2 > it);
+		ASSERT_FALSE(it3 > it);
+
+		ASSERT_FALSE(it2 <= it);
+		ASSERT_TRUE(it3 <= it);
+
+		ASSERT_FALSE(it2 < it);
+		ASSERT_FALSE(it3 < it);
+	}
+
+	// Read only (const)
+	{
+		JsonArray::const_iterator it = m_array.cbegin();
+
+		ASSERT_EQ(1, (*it).toInteger());
+		ASSERT_EQ(1, it->toInteger());
+		ASSERT_EQ("hello", it[1].toString());
+		ASSERT_TRUE(it[2].isTrue());
+
+		JsonArray::const_iterator it2 = it + 1;
+		ASSERT_EQ(1, it2[-1].toInteger());
+		ASSERT_EQ("hello", it2->toString());
+		ASSERT_TRUE(it2[1].isTrue());
+
+		JsonArray::const_iterator it3 = it;
+		ASSERT_TRUE(it2 != it);
+		ASSERT_FALSE(it3 != it);
+
+		ASSERT_FALSE(it2 == it);
+		ASSERT_TRUE(it3 == it);
+
+		ASSERT_TRUE(it3 >= it);
+		ASSERT_TRUE(it2 >= it);
+
+		ASSERT_TRUE(it2 > it);
+		ASSERT_FALSE(it3 > it);
+
+		ASSERT_FALSE(it2 <= it);
+		ASSERT_TRUE(it3 <= it);
+
+		ASSERT_FALSE(it2 < it);
+		ASSERT_FALSE(it3 < it);
+	}
+}
+
+TEST_F(ArrayIteratorsTest, assign)
+{
+	// Assign (non const)
+	{
+		JsonArray::iterator it = m_array.begin();
+
+		*it = JsonValue(9999);
+
+		ASSERT_EQ(3, static_cast<int>(m_array.size()));
+		ASSERT_EQ(9999, it->toInteger());
+		ASSERT_EQ(9999, m_array[0].toInteger());
+	}
+}
+
+TEST_F(ArrayIteratorsTest, assignConst)
+{
+	// Assign (const)
+	{
+		JsonArray::const_iterator it = m_array.cbegin();
+
+		*it = JsonValue(9999);
+
+		ASSERT_EQ(3, static_cast<int>(m_array.size()));
+		ASSERT_EQ(1, it->toInteger());
+		ASSERT_EQ(1, m_array[0].toInteger());
+	}
+}
+
+TEST_F(ArrayIteratorsTest, castToRef)
+{
+	JsonArray array{1, 2, 3};
+	int i = 1;
+
+	for (const JsonValue &v : array)
+	{
+		ASSERT_EQ(i++, v.toInteger());
+	}
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/OptionParser/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,229 @@
+/*
+ * main.cpp -- main test file for OptionParser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <OptionParser.h>
+
+/* --------------------------------------------------------
+ * Short options
+ * -------------------------------------------------------- */
+
+TEST(Short, simpleNoArg)
+{
+	OptionParser parser{
+		{ "a", "",	Option::NoArg	},
+		{ "b", "",	Option::NoArg	}
+	};
+
+	OptionPack pack = parser.parse({ "-a", "-b" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(2, static_cast<int>(pack.size()));
+	ASSERT_EQ(2, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "a");
+	ASSERT_TRUE(pack[1] == "b");
+}
+
+TEST(Short, simpleArg)
+{
+	OptionParser parser{
+		{ "v", "",	Option::NoArg	},
+		{ "c", "",			}
+	};
+
+	OptionPack pack = parser.parse({ "-v", "-cfoo.conf" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(2, static_cast<int>(pack.size()));
+	ASSERT_EQ(2, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "v");
+	ASSERT_TRUE(pack[1] == "c");
+	ASSERT_EQ("foo.conf", pack[1].value());
+}
+
+TEST(Short, spacedArg)
+{
+	OptionParser parser{
+		{ "v", "",	Option::NoArg	},
+		{ "c", "",			}
+	};
+
+	OptionPack pack = parser.parse({ "-v", "-c", "foo.conf" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(2, static_cast<int>(pack.size()));
+	ASSERT_EQ(3, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "v");
+	ASSERT_TRUE(pack[1] == "c");
+	ASSERT_EQ("foo.conf", pack[1].value());
+}
+
+TEST(Short, compacted)
+{
+	OptionParser parser{
+		{ "a", "",	Option::NoArg	},
+		{ "b", "",	Option::NoArg	},
+		{ "c", "",	Option::NoArg	},
+	};
+
+	OptionPack pack = parser.parse({ "-abc" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(3, static_cast<int>(pack.size()));
+	ASSERT_EQ(1, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "a");
+	ASSERT_TRUE(pack[1] == "b");
+	ASSERT_TRUE(pack[2] == "c");
+}
+
+TEST(Short, compactedArg)
+{
+	OptionParser parser{
+		{ "a", "",			},
+		{ "b", "",			},
+		{ "c", "",			},
+	};
+
+	OptionPack pack = parser.parse({ "-abc" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(1, static_cast<int>(pack.size()));
+	ASSERT_EQ(1, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "a");
+}
+
+/* --------------------------------------------------------
+ * Long options
+ * -------------------------------------------------------- */
+
+TEST(Long, simple)
+{
+	OptionParser parser{
+		{ "",	"verbose",	Option::NoArg	},
+		{ "",	"fullscreen",	Option::NoArg	}
+	};
+
+	OptionPack pack = parser.parse({ "--fullscreen" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(1, static_cast<int>(pack.size()));
+	ASSERT_EQ(1, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "fullscreen");
+}
+
+TEST(Long, simpleArg)
+{
+	OptionParser parser{
+		{ "", "config",			},
+		{ "", "level",			}
+	};
+
+	OptionPack pack = parser.parse({ "--config", "config.conf", "--level", "2" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(2, static_cast<int>(pack.size()));
+	ASSERT_EQ(4, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "config");
+	ASSERT_EQ("config.conf", pack[0].value());
+	ASSERT_TRUE(pack[1] == "level");
+	ASSERT_EQ("2", pack[1].value());
+}
+
+/* --------------------------------------------------------
+ * Combined
+ * -------------------------------------------------------- */
+
+TEST(Combined, simple)
+{
+	OptionParser parser{
+		{ "v", "verbose",	Option::NoArg	},
+		{ "l", "level",		Option::NoArg	}
+	};
+
+	OptionPack pack = parser.parse({ "-v", "-l", "--verbose", "--level" });
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_TRUE(pack[0] == "v" && pack[0] == "verbose");
+	ASSERT_TRUE(pack[1] == "l" && pack[1] == "level");
+	ASSERT_TRUE(pack[2] == "v" && pack[2] == "verbose");
+	ASSERT_TRUE(pack[3] == "l" && pack[3] == "level");
+}
+
+/* --------------------------------------------------------
+ * Flags
+ * -------------------------------------------------------- */
+
+TEST(Flags, standard)
+{
+	// No flags, parse unless there is an argument which is not an option
+	OptionParser parser{
+		{ "v", "",		Option::NoArg	}
+	};
+
+	OptionPack pack = parser.parse({ "-v", "install", "malikania" });
+
+	ASSERT_FALSE(pack);
+
+	ASSERT_EQ(1, static_cast<int>(pack.size()));
+	ASSERT_EQ(1, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "v");
+}
+
+TEST(Flags, unstrict)
+{
+	// No flags, parse unless there is an argument which is not an option
+	OptionParser parser{
+		{ "v", "",		Option::NoArg	},
+		{ "d", "",				}
+	};
+
+	OptionPack pack = parser.parse({ "-v", "install", "malikania", "-d", "/usr/local" }, OptionParser::Unstrict);
+
+	ASSERT_TRUE(pack);
+
+	ASSERT_EQ(2, static_cast<int>(pack.size()));
+	ASSERT_EQ(5, pack.parsed());
+
+	ASSERT_TRUE(pack[0] == "v");
+	ASSERT_TRUE(pack[1] == "d");
+	ASSERT_EQ("/usr/local", pack[1].value());
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Pack/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,508 @@
+/*
+ * TestPack.cpp -- test the pack serializer
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sstream>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <Pack.h>
+
+struct Point
+{
+	uint32_t width{};
+	uint32_t height{};
+
+	Point() = default;
+
+	Point(uint32_t width, uint32_t height)
+		: width(width)
+		, height(height)
+	{
+	}
+
+	inline bool operator==(const Point &other) const
+	{
+		return width == other.width && height == other.height;
+	}
+};
+
+template <>
+struct Pack::TypeInfo<Point> : public Pack::Serializable
+{
+	static void serialize(PackWriter &writer, const Point &point)
+	{
+		writer << point.width << point.height;
+	}
+
+	static void unserialize(PackReader &reader, Point &point)
+	{
+		reader >> point.width >> point.height;
+	}
+};
+
+TEST(File, simpleLittleEndian)
+{
+	uint8_t u8(1), r8;
+	uint16_t u16(2), r16;
+	uint32_t u32(3), r32;
+	uint64_t u64(4), r64;
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Little};
+			writer << u8 << u16 << u32 << u64;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Little};
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(File, simpleBigEndian)
+{
+	uint8_t u8(1), r8;
+	uint16_t u16(2), r16;
+	uint32_t u32(3), r32;
+	uint64_t u64(4), r64;
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Big};
+			writer << u8 << u16 << u32 << u64;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Big};
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(File, arrayLittleEndian)
+{
+	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
+	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
+	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
+	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
+
+	std::vector<uint8_t> r8(8);
+	std::vector<uint16_t> r16(8);
+	std::vector<uint32_t> r32(8);
+	std::vector<uint64_t> r64(8);
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Little};
+
+			writer << u8 << u16 << u32 << u64;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Little};
+
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(File, arrayBigEndian)
+{
+	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
+	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
+	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
+	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
+
+	std::vector<uint8_t> r8(8);
+	std::vector<uint16_t> r16(8);
+	std::vector<uint32_t> r32(8);
+	std::vector<uint64_t> r64(8);
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Big};
+
+			writer << u8 << u16 << u32 << u64;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Big};
+
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(File, serializeSimpleLittleEndian)
+{
+	Point point{200, 400};
+	Point result;
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Little};
+
+			writer << point;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Little};
+
+		reader >> result;
+
+		ASSERT_EQ(point, result);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(File, serializeSimpleBigEndian)
+{
+	Point point{200, 400};
+	Point result;
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Big};
+
+			writer << point;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Big};
+
+		reader >> result;
+
+		ASSERT_EQ(point, result);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(File, serializeArrayLittleEndian)
+{
+	std::vector<Point> points{{10, 20}, {30, 40}};
+	std::vector<Point> rpoints(2);
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Little};
+
+			writer << points;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Little};
+
+		reader >> rpoints;
+
+		ASSERT_EQ(points, rpoints);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(File, serializeArrayBigEndian)
+{
+	std::vector<Point> points{{10, 20}, {30, 40}};
+	std::vector<Point> rpoints(2);
+
+	remove("output.bin");
+
+	try {
+		{
+			PackFileWriter writer{"output.bin", Pack::Big};
+
+			writer << points;
+		}
+
+		PackFileReader reader{"output.bin", Pack::Big};
+
+		reader >> rpoints;
+
+		ASSERT_EQ(points, rpoints);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(String, simpleLittleEndian)
+{
+	uint8_t u8(1), r8;
+	uint16_t u16(2), r16;
+	uint32_t u32(3), r32;
+	uint64_t u64(4), r64;
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Little};
+			writer << u8 << u16 << u32 << u64;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Little};
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(String, simpleBigEndian)
+{
+	uint8_t u8(1), r8;
+	uint16_t u16(2), r16;
+	uint32_t u32(3), r32;
+	uint64_t u64(4), r64;
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Big};
+			writer << u8 << u16 << u32 << u64;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Big};
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(String, arrayLittleEndian)
+{
+	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
+	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
+	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
+	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
+
+	std::vector<uint8_t> r8(8);
+	std::vector<uint16_t> r16(8);
+	std::vector<uint32_t> r32(8);
+	std::vector<uint64_t> r64(8);
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Little};
+
+			writer << u8 << u16 << u32 << u64;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Little};
+
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(String, arrayBigEndian)
+{
+	std::vector<uint8_t> u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
+	std::vector<uint16_t> u16 { 10, 20, 30, 40, 50, 60, 70, 80 };
+	std::vector<uint32_t> u32 { 100, 200, 300, 400, 500, 600, 700, 800 };
+	std::vector<uint64_t> u64 { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 };
+
+	std::vector<uint8_t> r8(8);
+	std::vector<uint16_t> r16(8);
+	std::vector<uint32_t> r32(8);
+	std::vector<uint64_t> r64(8);
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Big};
+
+			writer << u8 << u16 << u32 << u64;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Big};
+
+		reader >> r8 >> r16 >> r32 >> r64;
+
+		ASSERT_EQ(u8, r8);
+		ASSERT_EQ(u16, r16);
+		ASSERT_EQ(u32, r32);
+		ASSERT_EQ(u64, r64);
+	} catch (const std::exception &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(String, serializeSimpleLittleEndian)
+{
+	Point point{200, 400};
+	Point result;
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Little};
+
+			writer << point;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Little};
+
+		reader >> result;
+
+		ASSERT_EQ(point, result);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(String, serializeSimpleBigEndian)
+{
+	Point point{200, 400};
+	Point result;
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Big};
+
+			writer << point;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Big};
+
+		reader >> result;
+
+		ASSERT_EQ(point, result);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(String, serializeArrayLittleEndian)
+{
+	std::vector<Point> points{{10, 20}, {30, 40}};
+	std::vector<Point> rpoints(2);
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Little};
+
+			writer << points;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Little};
+
+		reader >> rpoints;
+
+		ASSERT_EQ(points, rpoints);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST(String, serializeArrayBigEndian)
+{
+	std::vector<Point> points{{10, 20}, {30, 40}};
+	std::vector<Point> rpoints(2);
+
+	try {
+		std::string input;
+
+		{
+			PackStringWriter writer{Pack::Big};
+
+			writer << points;
+			input = writer.buffer();
+		}
+
+		PackStringReader reader{std::move(input), Pack::Big};
+
+		reader >> rpoints;
+
+		ASSERT_EQ(points, rpoints);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Parser/configs/multi.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,7 @@
+[entity]
+name	= "Player"
+version	= 1.0
+
+[entity]
+name	= "Subwinner"
+version	= 2.0
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Parser/configs/simple.conf	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,4 @@
+[general]
+option1=1
+option2 =2
+option3 = 3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Parser/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,98 @@
+/*
+ * TestParser.cpp -- test the config file parser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <Parser.h>
+
+TEST(Basic, simple)
+{
+	try {
+		Parser parser("Parser/simple.conf");
+
+		const auto &s = parser.getSection("general");
+		ASSERT_EQ("general", s.getName());
+
+		const auto &o1 = s.getOption<std::string>("option1");
+		ASSERT_EQ("1", o1);
+
+		const auto &o2 = s.getOption<std::string>("option2");
+		ASSERT_EQ("2", o2);
+
+		const auto &o3 = s.getOption<std::string>("option3");
+		ASSERT_EQ("3", o3);
+	} catch (const std::out_of_range &error) {
+		FAIL();
+	} catch (const std::runtime_error &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(Basic, multi)
+{
+	try {
+		Parser parser("Parser/multi.conf");
+		int i(0);
+
+		parser.findSections("entity", [&] (const Section &s) {
+			if (i++ == 0) {
+				ASSERT_EQ("Player", s.getOption<std::string>("name"));
+				ASSERT_EQ("1.0", s.getOption<std::string>("version"));
+			} else {
+				ASSERT_EQ("Subwinner", s.getOption<std::string>("name"));
+				ASSERT_EQ("2.0", s.getOption<std::string>("version"));
+			}
+		});
+
+		ASSERT_EQ(2, i);
+	} catch (const std::out_of_range &error) {
+		FAIL();
+	} catch (const std::runtime_error &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST(Basic, multiNoredef)
+{
+	try {
+		Parser parser("Parser/multi.conf", Parser::DisableRedefinition);
+		int i(0);
+
+		parser.findSections("entity", [&] (const Section &s) {
+			if (i++ == 0) {
+				ASSERT_EQ("Player", s.getOption<std::string>("name"));
+				ASSERT_EQ("1.0", s.getOption<std::string>("version"));
+			}
+		});
+
+		ASSERT_EQ(1, i);
+	} catch (const std::out_of_range &error) {
+		FAIL();
+	} catch (const std::runtime_error &error) {
+		FAIL() << error.what();
+	}
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Socket/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,709 @@
+/*
+ * main.cpp -- test sockets
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <chrono>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include "Socket.h"
+#include "SocketAddress.h"
+#include "SocketListener.h"
+#include "SocketSsl.h"
+#include "SocketTcp.h"
+#include "SocketUdp.h"
+
+using namespace address;
+using namespace std::literals::chrono_literals;
+
+/* --------------------------------------------------------
+ * TCP tests
+ * -------------------------------------------------------- */
+
+class TcpServerTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	TcpServerTest()
+	{
+		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+	}
+
+	~TcpServerTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
+
+TEST_F(TcpServerTest, connect)
+{
+	m_tserver = std::thread([this] () {
+		m_server.bind(Internet("*", 16000, AF_INET));
+
+		ASSERT_EQ(SocketState::Bound, m_server.state());
+
+		m_server.listen();
+		m_server.accept();
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+
+		ASSERT_EQ(SocketState::Connected, m_client.state());
+
+		m_client.close();
+	});
+}
+
+TEST_F(TcpServerTest, io)
+{
+	m_tserver = std::thread([this] () {
+		m_server.bind(Internet("*", 16000, AF_INET));
+		m_server.listen();
+
+		auto client = m_server.accept();
+		auto msg = client.recv(512);
+
+		ASSERT_EQ("hello world", msg);
+
+		client.send(msg);
+		client.close();
+
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello world");
+
+		ASSERT_EQ("hello world", m_client.recv(512));
+
+		m_client.close();
+	});
+}
+
+/* --------------------------------------------------------
+ * UDP tests
+ * -------------------------------------------------------- */
+
+class UdpServerTest : public testing::Test {
+protected:
+	SocketUdp m_server{AF_INET, 0};
+	SocketUdp m_client{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	UdpServerTest()
+	{
+		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+	}
+
+	~UdpServerTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
+
+TEST_F(UdpServerTest, io)
+{
+	m_tserver = std::thread([this] () {
+		SocketAddress info;
+
+		m_server.bind(Internet("*", 16000, AF_INET));
+
+		auto msg = m_server.recvfrom(512, info);
+
+		ASSERT_EQ("hello world", msg);
+
+		m_server.sendto(msg, info);
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		Internet info("127.0.0.1", 16000, AF_INET);
+
+		m_client.sendto("hello world", info);
+
+		ASSERT_EQ("hello world", m_client.recvfrom(512, info));
+
+		m_client.close();
+	});
+}
+
+/* --------------------------------------------------------
+ * Listener tests (standard)
+ * -------------------------------------------------------- */
+
+class ListenerTest : public testing::Test {
+protected:
+	SocketListener m_listener;
+	SocketTcp socket1{AF_INET, 0};
+	SocketUdp socket2{AF_INET, 0};
+
+public:
+	~ListenerTest()
+	{
+		socket1.close();
+		socket2.close();
+	}
+};
+
+TEST_F(ListenerTest, set)
+{
+	m_listener.set(socket1, SocketListener::Read);
+
+	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
+	ASSERT_EQ(SocketListener::Read, m_listener.begin()->second);
+
+	m_listener.set(socket1, SocketListener::Write);
+
+	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
+	ASSERT_EQ(0x3, m_listener.begin()->second);
+
+	// Fake a re-insert of the same socket
+	m_listener.set(socket1, SocketListener::Write);
+
+	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
+	ASSERT_EQ(0x3, m_listener.begin()->second);
+
+	// Add an other socket now
+	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
+
+	ASSERT_EQ(2, static_cast<int>(m_listener.size()));
+
+	for (auto &pair : m_listener) {
+		ASSERT_EQ(0x3, pair.second);
+		ASSERT_TRUE(pair.first == socket1 || pair.first == socket2);
+	}
+}
+
+TEST_F(ListenerTest, unset)
+{
+	m_listener.set(socket1, SocketListener::Read | SocketListener::Write);
+	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
+
+	m_listener.unset(socket1, SocketListener::Read);
+
+	ASSERT_EQ(2, static_cast<int>(m_listener.size()));
+
+	// Use a for loop since it can be ordered differently
+	for (auto &pair : m_listener) {
+		if (pair.first == socket1) {
+			ASSERT_EQ(0x2, pair.second);
+		} else if (pair.first == socket2) {
+			ASSERT_EQ(0x3, pair.second);
+		}
+	}
+
+	m_listener.unset(socket1, SocketListener::Write);
+
+	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
+	ASSERT_EQ(0x3, m_listener.begin()->second);
+}
+
+TEST_F(ListenerTest, remove)
+{
+	m_listener.set(socket1, SocketListener::Read | SocketListener::Write);
+	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
+	m_listener.remove(socket1);
+
+	ASSERT_EQ(1, static_cast<int>(m_listener.size()));
+	ASSERT_EQ(0x3, m_listener.begin()->second);
+}
+
+TEST_F(ListenerTest, clear)
+{
+	m_listener.set(socket1, SocketListener::Read | SocketListener::Write);
+	m_listener.set(socket2, SocketListener::Read | SocketListener::Write);
+	m_listener.clear();
+
+	ASSERT_EQ(0, static_cast<int>(m_listener.size()));
+}
+
+/* --------------------------------------------------------
+ * Listener: poll
+ * -------------------------------------------------------- */
+
+#if defined(SOCKET_HAVE_POLL)
+
+class ListenerPollTest : public testing::Test {
+protected:
+	SocketListener m_listener{SocketMethod::Poll};
+	SocketTcp m_masterTcp{AF_INET, 0};
+	SocketTcp m_clientTcp{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	ListenerPollTest()
+	{
+		m_masterTcp.set(SOL_SOCKET, SO_REUSEADDR, 1);
+		m_masterTcp.bind(Internet("*", 16000, AF_INET));
+		m_masterTcp.listen();
+	}
+
+	~ListenerPollTest()
+	{
+		if (m_tserver.joinable()) {
+			m_tserver.join();
+		}
+		if (m_tclient.joinable()) {
+			m_tclient.join();
+		}
+	}
+};
+
+TEST_F(ListenerPollTest, accept)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_listener.set(m_masterTcp, SocketListener::Read);
+			m_listener.select();
+			m_masterTcp.accept();
+			m_masterTcp.close();
+		} catch (const std::exception &ex) {
+			FAIL() << ex.what();
+		}
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
+	});
+}
+
+TEST_F(ListenerPollTest, recv)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_listener.set(m_masterTcp, SocketListener::Read);
+			m_listener.select();
+
+			auto sc = m_masterTcp.accept();
+
+			ASSERT_EQ("hello", sc.recv(512));
+
+			m_masterTcp.close();
+		} catch (const std::exception &ex) {
+			FAIL() << ex.what();
+		}
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_clientTcp.send("hello");
+	});
+}
+
+#endif
+
+/* --------------------------------------------------------
+ * Listener: select
+ * -------------------------------------------------------- */
+
+class ListenerSelectTest : public testing::Test {
+protected:
+	SocketListener m_listener{SocketMethod::Select};
+	SocketTcp m_masterTcp{AF_INET, 0};
+	SocketTcp m_clientTcp{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	ListenerSelectTest()
+	{
+		m_masterTcp.set(SOL_SOCKET, SO_REUSEADDR, 1);
+		m_masterTcp.bind(Internet("*", 16000, AF_INET));
+		m_masterTcp.listen();
+	}
+
+	~ListenerSelectTest()
+	{
+		if (m_tserver.joinable()) {
+			m_tserver.join();
+		}
+		if (m_tclient.joinable()) {
+			m_tclient.join();
+		}
+	}
+};
+
+TEST_F(ListenerSelectTest, accept)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_listener.set(m_masterTcp, SocketListener::Read);
+			m_listener.select();
+			m_masterTcp.accept();
+			m_masterTcp.close();
+		} catch (const std::exception &ex) {
+			FAIL() << ex.what();
+		}
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
+	});
+}
+
+TEST_F(ListenerSelectTest, recv)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_listener.set(m_masterTcp, SocketListener::Read);
+			m_listener.select();
+
+			auto sc = m_masterTcp.accept();
+
+			ASSERT_EQ("hello", sc.recv(512));
+
+			m_masterTcp.close();
+		} catch (const std::exception &ex) {
+			FAIL() << ex.what();
+		}
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_clientTcp.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_clientTcp.send("hello");
+	});
+}
+
+/* --------------------------------------------------------
+ * Non-blocking connect
+ * -------------------------------------------------------- */
+
+class NonBlockingConnectTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	NonBlockingConnectTest()
+	{
+		m_client.setBlockMode(false);
+	}
+
+	~NonBlockingConnectTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
+
+TEST_F(NonBlockingConnectTest, success)
+{
+	m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+	m_server.bind(Internet("*", 16000, AF_INET));
+	m_server.listen();
+
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
+
+		m_server.close();
+		client.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		try {
+			m_client.waitConnect(Internet("127.0.0.1", 16000, AF_INET), 3000);
+		} catch (const SocketError &error) {
+			FAIL() << error.what();
+		}
+
+		ASSERT_EQ(SocketState::Connected, m_client.state());
+
+		m_client.close();
+	});
+}
+
+TEST_F(NonBlockingConnectTest, fail)
+{
+	/*
+	 * /!\ If you find a way to test this locally please tell me /!\
+	 */
+	m_tclient = std::thread([this] () {
+		try {
+			m_client.waitConnect(Internet("google.fr", 9000, AF_INET), 100);
+
+			FAIL() << "Expected exception, got success";
+		} catch (const SocketError &error) {
+			ASSERT_EQ(SocketError::Timeout, error.code());
+		}
+
+		m_client.close();
+	});
+}
+
+/* --------------------------------------------------------
+ * TCP accept
+ * -------------------------------------------------------- */
+
+class TcpAcceptTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	TcpAcceptTest()
+	{
+		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+		m_server.bind(Internet("*", 16000, AF_INET));
+		m_server.listen();
+	}
+
+	~TcpAcceptTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
+
+TEST_F(TcpAcceptTest, blockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_server.waitAccept(3000).close();
+		} catch (const SocketError &error) {
+			FAIL() << error.what();
+		}
+
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.close();
+	});
+}
+
+TEST_F(TcpAcceptTest, nonBlockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_server.setBlockMode(false);
+			m_server.waitAccept(3000).close();
+		} catch (const SocketError &error) {
+			FAIL() << error.what();
+		}
+
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.close();
+	});
+}
+
+TEST_F(TcpAcceptTest, nonBlockingWaitFail)
+{
+	// No client, no accept
+	try {
+		m_server.setBlockMode(false);
+		m_server.waitAccept(100).close();
+
+		FAIL() << "Expected exception, got success";
+	} catch (const SocketError &error) {
+		ASSERT_EQ(SocketError::Timeout, error.code());
+	}
+
+	m_server.close();
+}
+
+/* --------------------------------------------------------
+ * TCP recv
+ * -------------------------------------------------------- */
+
+class TcpRecvTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
+
+public:
+	TcpRecvTest()
+	{
+		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+		m_server.bind(Internet("*", 16000, AF_INET));
+		m_server.listen();
+	}
+
+	~TcpRecvTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
+
+TEST_F(TcpRecvTest, blockingSuccess)
+{
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
+
+		ASSERT_EQ("hello", client.recv(32));
+
+		client.close();
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello");
+		m_client.close();
+	});
+}
+
+TEST_F(TcpRecvTest, blockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
+
+		ASSERT_EQ("hello", client.waitRecv(32, 3000));
+
+		client.close();
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello");
+		m_client.close();
+	});
+}
+
+TEST_F(TcpRecvTest, nonBlockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
+
+		client.setBlockMode(false);
+
+		ASSERT_EQ("hello", client.waitRecv(32, 3000));
+
+		client.close();
+		m_server.close();
+	});
+
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello");
+		m_client.close();
+	});
+}
+
+/* --------------------------------------------------------
+ * Socket SSL
+ * -------------------------------------------------------- */
+
+class SslTest : public testing::Test {
+protected:
+	SocketSsl client{AF_INET, 0};
+};
+
+TEST_F(SslTest, connect)
+{
+	try {
+		client.connect(Internet("google.fr", 443, AF_INET));
+		client.close();
+	} catch (const SocketError &error) {
+		FAIL() << error.what();
+	}
+}
+
+TEST_F(SslTest, recv)
+{
+	try {
+		client.connect(Internet("google.fr", 443, AF_INET));
+		client.send("GET / HTTP/1.0\r\n\r\n");
+
+		std::string msg = client.recv(512);
+		std::string content = msg.substr(0, 18);
+
+		ASSERT_EQ("HTTP/1.0 302 Found", content);
+
+		client.close();
+	} catch (const SocketError &error) {
+		FAIL() << error.what();
+	}
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Treenode/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,1561 @@
+/*
+ * main.cpp -- main test file for TreeNode
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <chrono>
+#include <iostream>
+#include <iterator>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <TreeNode.h>
+
+class Object final : public TreeNode<Object> {
+private:
+	std::string	m_name;
+
+public:
+	Object(std::string name)
+		: TreeNode()
+	{
+		m_name = std::move(name);
+	}
+
+	const std::string &name() const
+	{
+		return m_name;
+	}
+
+	friend bool operator==(const Object &o1, const Object &o2);
+};
+
+bool operator==(const Object &o1, const Object &o2)
+{
+	return o1.name() == o2.name();
+}
+
+/*
+ * Random trees are created and then we test each node with the following preferred order:
+ *
+ * ASSERT_(TRUE|FALSE) isRoot()
+ * ASSERT_(TRUE|FALSE) isLeaf()
+ * ASSERT_EQ countChildren()
+ * ASSERT_EQ() name()
+ * ASSERT_TRUE & addresses
+ */
+
+/* --------------------------------------------------------
+ * Basic construction and insertion
+ * -------------------------------------------------------- */
+
+/*
+ * @root
+ */
+TEST(Basic, construct)
+{
+	Object object("root");
+
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_TRUE(object.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+}
+
+/*
+ * @root -> append move -> @root
+ *                         |
+ *                         @a
+ */
+TEST(Insertion, simpleAppendMove)
+{
+	Object object("root");
+	Object a("a");
+
+	object.append(std::move(a));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test moved a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original a
+	ASSERT_TRUE(a.isRoot());
+	ASSERT_TRUE(a.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(a.countChildren()));
+}
+
+/*
+ * @root -> append copy -> @root
+ *                         |
+ *                         @a
+ */
+TEST(Insertion, simpleAppendCopy)
+{
+	Object object("root");
+	Object copy("b");
+
+	object.append(copy);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test copied b
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ("b", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy.countChildren()));
+	ASSERT_EQ("b", copy.name());
+}
+
+/*
+ * @root -> append move -> @root
+ *                        / \
+ *                      1@   @2
+ */
+TEST(Insertion, doubleAppendMove)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.append(std::move(o1));
+	object.append(std::move(o2));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test moved 1
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("1", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test moved 2
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ("2", object[1].name());
+	ASSERT_EQ(0, static_cast<int>(object[1].countChildren()));
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o1.countChildren()));
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o2.countChildren()));
+}
+
+/*
+ * @root -> append copy -> @root
+ *                        / \
+ *                      1@   @2
+ */
+TEST(Insertion, doubleAppendCopy)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.append(o1);
+	object.append(o2);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test copied 1
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("1", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test copied 2
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[1].countChildren()));
+	ASSERT_EQ("2", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o1.countChildren()));
+	ASSERT_EQ("1", o1.name());
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o2.countChildren()));
+	ASSERT_EQ("2", o2.name());
+}
+
+/*
+ * @root -> push move -> @root
+ *                       |
+ *                       @a
+ */
+TEST(Insertion, simplePushMove)
+{
+	Object object("root");
+	Object a("a");
+
+	object.push(std::move(a));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("a", object[0].name());
+
+	// test moved a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original a
+	ASSERT_TRUE(a.isRoot());
+	ASSERT_TRUE(a.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(a.countChildren()));
+}
+
+/*
+ * @root -> push copy -> @root
+ *                       |
+ *                       @a
+ */
+TEST(Insertion, simplePushCopy)
+{
+	Object object("root");
+	Object copy("a");
+
+	object.push(copy);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("a", object[0].name());
+
+	// test copied a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy.countChildren()));
+	ASSERT_EQ("a", copy.name());
+}
+
+/*
+ * @root -> push move -> @root
+ *                      / \
+ *                    2@   @1
+ */
+TEST(Insertion, doublePushMove)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.push(std::move(o1));
+	object.push(std::move(o2));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test moved 2
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("2", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test moved 1
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ("1", object[1].name());
+	ASSERT_EQ(0, static_cast<int>(object[1].countChildren()));
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o1.countChildren()));
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o2.countChildren()));
+}
+
+/*
+ * @root -> push copy -> @root
+ *                      / \
+ *                    2@   @1
+ */
+TEST(Insertion, doublePushCopy)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.push(o1);
+	object.push(o2);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test copied 2
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("2", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test copied 1
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[1].countChildren()));
+	ASSERT_EQ("1", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o1.countChildren()));
+	ASSERT_EQ("1", o1.name());
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(o2.countChildren()));
+	ASSERT_EQ("2", o2.name());
+}
+
+/* --------------------------------------------------------
+ * Sub insertion
+ * -------------------------------------------------------- */
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b
+ *        / \   / \
+ *      c@  d@ @e  @f
+ */
+TEST(SubInsert, append)
+{
+	Object object("root");
+
+	object.append(Object("a"));
+	object.append(Object("b"));
+
+	object[0].append(Object("c"));
+	object[0].append(Object("d"));
+	object[1].append(Object("e"));
+	object[1].append(Object("f"));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_FALSE(object[0].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test b
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_FALSE(object[1].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object[1].countChildren()));
+	ASSERT_EQ("b", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test c
+	ASSERT_FALSE(object[0][0].isRoot());
+	ASSERT_TRUE(object[0][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0][0].countChildren()));
+	ASSERT_EQ("c", object[0][0].name());
+	ASSERT_TRUE(&object[0] == &object[0][0].parent());
+
+	// test d
+	ASSERT_FALSE(object[0][1].isRoot());
+	ASSERT_TRUE(object[0][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0][1].countChildren()));
+	ASSERT_EQ("d", object[0][1].name());
+	ASSERT_TRUE(&object[0] == &object[0][1].parent());
+
+	// test e
+	ASSERT_FALSE(object[1][0].isRoot());
+	ASSERT_TRUE(object[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[1][0].countChildren()));
+	ASSERT_EQ("e", object[1][0].name());
+	ASSERT_TRUE(&object[1] == &object[1][0].parent());
+
+	// test f
+	ASSERT_FALSE(object[1][1].isRoot());
+	ASSERT_TRUE(object[1][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[1][1].countChildren()));
+	ASSERT_EQ("f", object[1][1].name());
+	ASSERT_TRUE(&object[1] == &object[1][1].parent());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        b@     @a
+ *        / \   / \
+ *      d@  c@ @f  @e
+ */
+TEST(SubInsert, push)
+{
+	Object object("root");
+
+	object.push(Object("a"));
+	object.push(Object("b"));
+
+	object[0].push(Object("c"));
+	object[0].push(Object("d"));
+	object[1].push(Object("e"));
+	object[1].push(Object("f"));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object.countChildren()));
+	ASSERT_EQ("root", object.name());
+
+	// test b
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_FALSE(object[0].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object[0].countChildren()));
+	ASSERT_EQ("b", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test a
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_FALSE(object[1].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(object[1].countChildren()));
+	ASSERT_EQ("a", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test d
+	ASSERT_FALSE(object[0][0].isRoot());
+	ASSERT_TRUE(object[0][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0][0].countChildren()));
+	ASSERT_EQ("d", object[0][0].name());
+	ASSERT_TRUE(&object[0] == &object[0][0].parent());
+
+	// test c
+	ASSERT_FALSE(object[0][1].isRoot());
+	ASSERT_TRUE(object[0][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[0][1].countChildren()));
+	ASSERT_EQ("c", object[0][1].name());
+	ASSERT_TRUE(&object[0] == &object[0][1].parent());
+
+	// test f
+	ASSERT_FALSE(object[1][0].isRoot());
+	ASSERT_TRUE(object[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[1][0].countChildren()));
+	ASSERT_EQ("f", object[1][0].name());
+	ASSERT_TRUE(&object[1] == &object[1][0].parent());
+
+	// test e
+	ASSERT_FALSE(object[1][1].isRoot());
+	ASSERT_TRUE(object[1][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(object[1][1].countChildren()));
+	ASSERT_EQ("e", object[1][1].name());
+	ASSERT_TRUE(&object[1] == &object[1][1].parent());
+}
+
+/* --------------------------------------------------------
+ * Move constructor
+ * -------------------------------------------------------- */
+
+TEST(MoveConstructor, simple)
+{
+	Object root("root");
+	Object moved(std::move(root));
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root.countChildren()));
+
+	// test moved
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved.countChildren()));
+	ASSERT_EQ("root", moved.name());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b
+ */
+TEST(MoveConstructor, oneLevel)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object moved(std::move(root));
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_EQ(2, static_cast<int>(moved.countChildren()));
+	ASSERT_EQ("a", moved[0].name());
+	ASSERT_EQ("b", moved[1].name());
+	ASSERT_EQ("root", moved[0].parent().name());
+	ASSERT_EQ("root", moved[1].parent().name());
+	ASSERT_TRUE(&moved == &moved[0].parent());
+	ASSERT_TRUE(&moved == &moved[1].parent());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *
+ */
+TEST(MoveConstructor, twoLevels)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+
+	Object moved(std::move(root));
+
+	// test root
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_EQ(2, static_cast<int>(moved.countChildren()));
+
+	// test a, b
+	ASSERT_EQ("a", moved[0].name());
+	ASSERT_EQ("b", moved[1].name());
+	ASSERT_EQ(2, static_cast<int>(moved[0].countChildren()));
+	ASSERT_EQ(2, static_cast<int>(moved[1].countChildren()));
+	ASSERT_EQ("root", moved[0].parent().name());
+	ASSERT_EQ("root", moved[1].parent().name());
+	ASSERT_TRUE(&moved == &moved[0].parent());
+	ASSERT_TRUE(&moved == &moved[1].parent());
+
+	// test c, d
+	ASSERT_EQ("c", moved[0][0].name());
+	ASSERT_EQ("d", moved[0][1].name());
+	ASSERT_EQ("a", moved[0][0].parent().name());
+	ASSERT_EQ("a", moved[0][1].parent().name());
+	ASSERT_TRUE(&moved[0] == &moved[0][0].parent());
+	ASSERT_TRUE(&moved[0] == &moved[0][1].parent());
+	ASSERT_TRUE(moved[0][0].isLeaf());
+	ASSERT_TRUE(moved[0][1].isLeaf());
+	ASSERT_FALSE(moved[0][0].isRoot());
+	ASSERT_FALSE(moved[0][1].isRoot());
+
+	// test e, f
+	ASSERT_EQ("e", moved[1][0].name());
+	ASSERT_EQ("f", moved[1][1].name());
+	ASSERT_EQ("b", moved[1][0].parent().name());
+	ASSERT_EQ("b", moved[1][1].parent().name());
+	ASSERT_TRUE(&moved[1] == &moved[1][0].parent());
+	ASSERT_TRUE(&moved[1] == &moved[1][1].parent());
+	ASSERT_TRUE(moved[1][0].isLeaf());
+	ASSERT_TRUE(moved[1][1].isLeaf());
+	ASSERT_FALSE(moved[1][0].isRoot());
+	ASSERT_FALSE(moved[1][1].isRoot());
+}
+
+/* --------------------------------------------------------
+ * Copy constructor
+ * -------------------------------------------------------- */
+
+TEST(CopyConstructor, simple)
+{
+	Object root("root");
+	Object moved(root);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test copy
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved.countChildren()));
+	ASSERT_EQ("root", moved.name());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b
+ */
+TEST(CopyConstructor, oneLevel)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object copy(root);
+
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ("root", root.name());
+	ASSERT_EQ("root", copy.name());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("b", root[1].name());
+	ASSERT_EQ("a", copy[0].name());
+	ASSERT_EQ("b", copy[1].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+	ASSERT_TRUE(&root == &root[1].parent());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *
+ */
+TEST(CopyConstructor, twoLevels)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+
+	Object copy(root);
+
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ("root", root.name());
+	ASSERT_EQ("root", copy.name());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("a", copy[0].name());
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_EQ("c", copy[0][0].name());
+	ASSERT_EQ("d", root[0][1].name());
+	ASSERT_EQ("d", copy[0][1].name());
+	ASSERT_EQ("b", root[1].name());
+	ASSERT_EQ("b", copy[1].name());
+	ASSERT_EQ("e", root[1][0].name());
+	ASSERT_EQ("e", copy[1][0].name());
+	ASSERT_EQ("f", root[1][1].name());
+	ASSERT_EQ("f", copy[1][1].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+	ASSERT_TRUE(&root == &root[1].parent());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+	ASSERT_TRUE(&root[0] == &root[0][1].parent());
+	ASSERT_TRUE(&copy[0] == &copy[0][0].parent());
+	ASSERT_TRUE(&copy[0] == &copy[0][1].parent());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+	ASSERT_TRUE(&copy[1] == &copy[1][0].parent());
+	ASSERT_TRUE(&copy[1] == &copy[1][1].parent());
+}
+
+/* --------------------------------------------------------
+ * Move extraction
+ * -------------------------------------------------------- */
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> move -> @b
+ */
+TEST(MoveExtraction, simple)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object moved(std::move(root[1]));
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_TRUE(root[0].isLeaf());
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ(0, static_cast<int>(root[0].countChildren()));
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test b
+	ASSERT_TRUE(root[1].isLeaf());
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_EQ(0, static_cast<int>(root[1].countChildren()));
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test moved b
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved.countChildren()));
+	ASSERT_EQ("b", moved.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> move
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *                  \
+ *                   @g
+ */
+TEST(MoveExtraction, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object moved(std::move(root[1]));
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[0].countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[0][0].countChildren()));
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test d
+	ASSERT_FALSE(root[0][1].isRoot());
+	ASSERT_TRUE(root[0][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[0][1].countChildren()));
+	ASSERT_EQ("d", root[0][1].name());
+	ASSERT_TRUE(&root[0] == &root[0][1].parent());
+
+	// test b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_TRUE(root[1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1].countChildren()));
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test moved b
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_FALSE(moved.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(moved.countChildren()));
+	ASSERT_EQ("b", moved.name());
+
+	// test moved b-e
+	ASSERT_FALSE(moved[0].isRoot());
+	ASSERT_TRUE(moved[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved[0].countChildren()));
+	ASSERT_EQ("e", moved[0].name());
+	ASSERT_TRUE(&moved == &moved[0].parent());
+
+	// test moved b-f
+	ASSERT_FALSE(moved[1].isRoot());
+	ASSERT_FALSE(moved[1].isLeaf());
+	ASSERT_EQ(1, static_cast<int>(moved[1].countChildren()));
+	ASSERT_EQ("f", moved[1].name());
+	ASSERT_TRUE(&moved == &moved[1].parent());
+
+	// test moved b-g
+	ASSERT_FALSE(moved[1][0].isRoot());
+	ASSERT_TRUE(moved[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved[1][0].countChildren()));
+	ASSERT_EQ("g", moved[1][0].name());
+	ASSERT_TRUE(&moved[1] == &moved[1][0].parent());
+}
+
+/* --------------------------------------------------------
+ * Copy extraction
+ * -------------------------------------------------------- */
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> copy -> @b
+ */
+TEST(CopyExtraction, simple)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object copy(root[1]);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_TRUE(root[0].isLeaf());
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_EQ(0, static_cast<int>(root[0].countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test b
+	ASSERT_TRUE(root[1].isLeaf());
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_EQ(0, static_cast<int>(root[1].countChildren()));
+	ASSERT_EQ("b", root[1].name());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test copied b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy.countChildren()));
+	ASSERT_EQ("b", copy.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> copy
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *                  \
+ *                   @g
+ */
+TEST(CopyExtraction, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object copy(root[1]);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[0].countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[0][0].countChildren()));
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test d
+	ASSERT_FALSE(root[0][1].isRoot());
+	ASSERT_TRUE(root[0][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[0][1].countChildren()));
+	ASSERT_EQ("d", root[0][1].name());
+	ASSERT_TRUE(&root[0] == &root[0][1].parent());
+
+	// test b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_FALSE(root[1].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[1].countChildren()));
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test e
+	ASSERT_FALSE(root[1][0].isRoot());
+	ASSERT_TRUE(root[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1][0].countChildren()));
+	ASSERT_EQ("e", root[1][0].name());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+
+	// test f
+	ASSERT_FALSE(root[1][1].isRoot());
+	ASSERT_FALSE(root[1][1].isLeaf());
+	ASSERT_EQ(1, static_cast<int>(root[1][1].countChildren()));
+	ASSERT_EQ("f", root[1][1].name());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+
+	// test g
+	ASSERT_FALSE(root[1][1][0].isRoot());
+	ASSERT_TRUE(root[1][1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1][1][0].countChildren()));
+	ASSERT_EQ("g", root[1][1][0].name());
+	ASSERT_TRUE(&root[1][1] == &root[1][1][0].parent());
+
+	// test copied b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(copy.countChildren()));
+	ASSERT_EQ("b", copy.name());
+
+	// test copied b-e
+	ASSERT_FALSE(copy[0].isRoot());
+	ASSERT_TRUE(copy[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy[0].countChildren()));
+	ASSERT_EQ("e", copy[0].name());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+
+	// test copied b-f
+	ASSERT_FALSE(copy[1].isRoot());
+	ASSERT_FALSE(copy[1].isLeaf());
+	ASSERT_EQ(1, static_cast<int>(copy[1].countChildren()));
+	ASSERT_EQ("f", copy[1].name());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+
+	// test copied b-g
+	ASSERT_FALSE(copy[1][0].isRoot());
+	ASSERT_TRUE(copy[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy[1][0].countChildren()));
+	ASSERT_EQ("g", copy[1][0].name());
+	ASSERT_TRUE(&copy[1] == &copy[1][0].parent());
+}
+
+/* --------------------------------------------------------
+ * Move assignment
+ * -------------------------------------------------------- */
+
+/*
+ * @root -> @moved
+ */
+TEST(MoveAssignment, simple)
+{
+	Object root("root");
+	Object moved("dummy");
+
+	moved = std::move(root);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root.countChildren()));
+
+	// test moved
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved.countChildren()));
+	ASSERT_EQ("root", moved.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b <- move <- @x
+ *        / \   / \           / \
+ *      c@  d@ @e  @f       y@   @z
+ *                  \
+ *                   @g
+ */
+TEST(MoveAssignment, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object moved("x");
+
+	moved.append(Object("y"));
+	moved.append(Object("z"));
+
+	root[1] = std::move(moved);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[0].countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[0][0].countChildren()));
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test copied x to b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_FALSE(root[1].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[1].countChildren()));
+	ASSERT_EQ("x", root[1].name());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test y
+	ASSERT_FALSE(root[1][0].isRoot());
+	ASSERT_TRUE(root[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1][0].countChildren()));
+	ASSERT_EQ("y", root[1][0].name());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+
+	// test z
+	ASSERT_FALSE(root[1][1].isRoot());
+	ASSERT_TRUE(root[1][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1][1].countChildren()));
+	ASSERT_EQ("z", root[1][1].name());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+
+	// test moved
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(moved.countChildren()));
+}
+
+/* --------------------------------------------------------
+ * Copy assignment
+ * -------------------------------------------------------- */
+
+/*
+ * @root -> @copy
+ */
+TEST(CopyAssignment, simple)
+{
+	Object root("root");
+	Object copy("copy");
+
+	copy = root;
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test copied
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy.countChildren()));
+	ASSERT_EQ("root", copy.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b <- copy <- @x
+ *        / \   / \           / \
+ *      c@  d@ @e  @f       y@   @z
+ *                  \
+ *                   @g
+ */
+TEST(CopyAssignment, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object copy("x");
+
+	copy.append(Object("y"));
+	copy.append(Object("z"));
+
+	root[1] = copy;
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[0].countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[0][0].countChildren()));
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test copied x to b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_FALSE(root[1].isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root[1].countChildren()));
+	ASSERT_EQ("x", root[1].name());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test y
+	ASSERT_FALSE(root[1][0].isRoot());
+	ASSERT_TRUE(root[1][0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1][0].countChildren()));
+	ASSERT_EQ("y", root[1][0].name());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+
+	// test z
+	ASSERT_FALSE(root[1][1].isRoot());
+	ASSERT_TRUE(root[1][1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(root[1][1].countChildren()));
+	ASSERT_EQ("z", root[1][1].name());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+
+	// test original x
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(copy.countChildren()));
+	ASSERT_EQ("x", copy.name());
+
+	// test original y
+	ASSERT_FALSE(copy[0].isRoot());
+	ASSERT_TRUE(copy[0].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy[0].countChildren()));
+	ASSERT_EQ("y", copy[0].name());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+
+	// test original z
+	ASSERT_FALSE(copy[1].isRoot());
+	ASSERT_TRUE(copy[1].isLeaf());
+	ASSERT_EQ(0, static_cast<int>(copy[1].countChildren()));
+	ASSERT_EQ("z", copy[1].name());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+}
+
+/* --------------------------------------------------------
+ * Remove functions
+ * -------------------------------------------------------- */
+
+TEST(Remove, clear)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+	root.clear();
+
+	ASSERT_EQ(0, static_cast<int>(root.countChildren()));
+}
+
+TEST(Remove, index)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+	root.remove(2);
+
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("b", root[1].name());
+}
+
+TEST(Remove, ref)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+	root.remove(root[2]);
+
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("b", root[1].name());
+}
+
+TEST(Remove, same)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+	root.removeSame(Object("c"));
+
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("b", root[1].name());
+}
+
+/* --------------------------------------------------------
+ * Miscellaneous
+ * -------------------------------------------------------- */
+
+TEST(Misc, indexOf)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+
+	ASSERT_EQ(1, root.indexOf(root[1]));
+}
+
+TEST(Misc, indexOfFail)
+{
+	Object root("root");
+	Object notin("c");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+
+	ASSERT_EQ(-1, root.indexOf(notin));
+}
+
+TEST(Misc, indexOfSame)
+{
+	Object root("root");
+	Object same("a");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+
+	ASSERT_EQ(0, root.indexOfSame(same));
+}
+
+TEST(Misc, indexOfSameFail)
+{
+	Object root("root");
+	Object same("xyz");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+	root.append(Object("c"));
+
+	ASSERT_EQ(-1, root.indexOfSame(same));
+}
+
+TEST(Misc, inplaceFront)
+{
+	Object root("root");
+
+	root.pushNew("a");
+	root.pushNew("b");
+
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("b", root[0].name());
+	ASSERT_EQ("a", root[1].name());
+}
+
+TEST(Misc, inplaceBack)
+{
+	Object root("root");
+
+	root.appendNew("a");
+	root.appendNew("b");
+
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, static_cast<int>(root.countChildren()));
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("b", root[1].name());
+}
+
+TEST(Misc, map)
+{
+	Object root("root");
+	std::vector<Object> list;
+
+	root.appendNew("a");
+	root.appendNew("b");
+
+	root[0].appendNew("c");
+
+	root.map([&] (const auto &o) {
+		list.push_back(o);
+	});
+
+	ASSERT_EQ(4, static_cast<int>(list.size()));
+	ASSERT_EQ("root", list[0].name());
+	ASSERT_EQ("a", list[1].name());
+	ASSERT_EQ("c", list[2].name());
+	ASSERT_EQ("b", list[3].name());
+}
+
+TEST(Misc, flat)
+{
+	Object root("root");
+	std::vector<Object> list;
+
+	root.appendNew("a");
+	root.appendNew("b");
+
+	root[0].appendNew("c");
+	root.flat(std::back_inserter(list));
+
+	ASSERT_EQ(4, static_cast<int>(list.size()));
+	ASSERT_EQ("root", list[0].name());
+	ASSERT_EQ("a", list[1].name());
+	ASSERT_EQ("c", list[2].name());
+	ASSERT_EQ("b", list[3].name());
+}
+
+/* --------------------------------------------------------
+ * Search
+ * -------------------------------------------------------- */
+
+TEST(Search, returnsValue)
+{
+	Object root("root");
+
+	root.appendNew("a");
+	root.appendNew("b");
+
+	root[0].appendNew("c");
+
+	auto dummy = [] (Object &) {};
+
+	ASSERT_TRUE(root.search([] (const auto &v) { return v.name() == "a"; }, dummy));
+	ASSERT_TRUE(root.search([] (const auto &v) { return v.name() == "b"; }, dummy));
+	ASSERT_TRUE(root.search([] (const auto &v) { return v.name() == "c"; }, dummy));
+	ASSERT_FALSE(root.search([] (const auto &v) { return v.name() == "notavail"; }, dummy));
+}
+
+TEST(Search, returns)
+{
+	Object root("root");
+
+	root.appendNew("a");
+	root.appendNew("b");
+
+	root[0].appendNew("c");
+
+	try {
+		auto &a = root.search([] (const auto &o) {
+			return o.name() == "a";
+		});
+		auto &b = root.search([] (const auto &o) {
+			return o.name() == "b";
+		});
+		auto &c = root.search([] (const auto &o) {
+			return o.name() == "c";
+		});
+
+		ASSERT_EQ("a", a.name());
+		ASSERT_EQ("b", b.name());
+		ASSERT_EQ("c", c.name());
+
+		ASSERT_TRUE(&a == &root[0]);
+		ASSERT_TRUE(&b == &root[1]);
+		ASSERT_TRUE(&c == &root[0][0]);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Search, returnsFirst)
+{
+	Object root("root");
+
+	root.appendNew("a");
+	root.appendNew("a");
+	root.appendNew("a");
+
+	try {
+		auto &value = root.search([] (const auto &v) {
+			return v.name() == "a";
+		});
+
+		ASSERT_EQ("a", value.name());
+		ASSERT_TRUE(&value == &root[0]);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * Test inheritance
+ * -------------------------------------------------------- */
+
+class Animal : public TreeNode<Animal> {
+public:
+	virtual ~Animal() = default;
+	virtual std::string noise() const
+	{
+		return "standard";
+	}
+};
+
+class Cat final : public Animal {
+public:
+	std::string noise() const override
+	{
+		return "miaou";
+	}
+};
+
+class Dog final : public Animal {
+public:
+	std::string noise() const override
+	{
+		return "waouf";
+	}
+};
+
+TEST(Inheritance, basic)
+{
+	Animal root;
+
+	root.append(Animal());
+	root.append(Cat());
+	root.append(Dog());
+
+	ASSERT_EQ("standard", root[0].noise());
+	ASSERT_EQ("miaou", root[1].noise());
+	ASSERT_EQ("waouf", root[2].noise());
+}
+
+TEST(Inheritance, copy)
+{
+	Animal root;
+
+	root.append(Animal());
+	root.append(Cat());
+	root.append(Dog());
+
+	ASSERT_EQ("standard", root[0].noise());
+	ASSERT_EQ("miaou", root[1].noise());
+	ASSERT_EQ("waouf", root[2].noise());
+
+	Animal copy(root);
+
+	ASSERT_EQ("standard", copy[0].noise());
+	ASSERT_EQ("miaou", copy[1].noise());
+	ASSERT_EQ("waouf", copy[2].noise());
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Utf8/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,327 @@
+/*
+ * main.cpp -- main test file for Utf8
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * /!\ Be sure to keep this file with UTF-8 encoding /!\
+ */
+
+#include <gtest/gtest.h>
+
+#include <Utf8.h>
+
+using namespace testing;
+
+/* --------------------------------------------------------
+ * Conversion UTF32 -> UTF8
+ * -------------------------------------------------------- */
+
+TEST(Conversion32to8, ascii)
+{
+	try {
+		std::u32string u32{'a', 'b', 'c'};
+		std::string s = Utf8::toutf8(u32);
+
+		ASSERT_EQ("abc", s);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Conversion32to8, valid)
+{
+	try {
+		std::u32string u32{'a', /* é */ 233, 'c'};
+		std::string s = Utf8::toutf8(u32);
+
+		ASSERT_EQ("aéc", s);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Conversion32to8, invalid)
+{
+	try {
+		std::u32string u32{'a', 0xFFFFFFFF, 'c'};
+		std::string s = Utf8::toutf8(u32);
+
+		FAIL() << "expected a failure";
+	} catch (const std::exception &ex) {
+		SUCCEED();
+	}
+}
+
+/* --------------------------------------------------------
+ * Conversion UTF8 -> UTF32
+ * -------------------------------------------------------- */
+
+TEST(Conversion8to32, ascii)
+{
+	try {
+		std::string s{"abc"};
+		std::u32string expected{'a', 'b', 'c'};
+		std::u32string result = Utf8::toutf32(s);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Conversion8to32, valid)
+{
+	try {
+		std::string s{"aéc"};
+		std::u32string expected{'a', /* é */ 233, 'c'};
+		std::u32string result = Utf8::toutf32(s);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * UTF32 to upper
+ * -------------------------------------------------------- */
+
+TEST(Toupper32, ascii)
+{
+	try {
+		std::u32string u32{'a', 'b', 'c'};
+		std::u32string expected{'A', 'B', 'C'};
+		std::u32string result = Utf8::toupper(u32);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Toupper32, valid)
+{
+	try {
+		std::u32string u32{/* ä */ 228, /* ç */ 231, /* ë */ 235};
+		std::u32string expected{/* Ä */ 196, /* Ç */ 199, /* Ë */ 203};
+		std::u32string result = Utf8::toupper(u32);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Toupper32, invalid)
+{
+	try {
+		std::u32string u32{'a', 0xFFFFFFFF, 'b'};
+		std::u32string expected{'A', 0xFFFFFFFF, 'B'};
+		std::u32string result = Utf8::toupper(u32);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * UTF32 to lower
+ * -------------------------------------------------------- */
+
+TEST(Tolower32, ascii)
+{
+	try {
+		std::u32string u32{'A', 'B', 'C'};
+		std::u32string expected{'a', 'b', 'c'};
+		std::u32string result = Utf8::tolower(u32);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Tolower32, valid)
+{
+	try {
+		std::u32string u32{/* Ä */ 196, /* Ç */ 199, /* Ë */ 203};
+		std::u32string expected{/* ä */ 228, /* ç */ 231, /* ë */ 235};
+		std::u32string result = Utf8::tolower(u32);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Tolower32, invalid)
+{
+	try {
+		std::u32string u32{'A', 0xFFFFFFFF, 'B'};
+		std::u32string expected{'a', 0xFFFFFFFF, 'b'};
+		std::u32string result = Utf8::tolower(u32);
+
+		ASSERT_EQ(expected, result);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+/* --------------------------------------------------------
+ * UTF8 to upper
+ * -------------------------------------------------------- */
+
+TEST(Toupper8, ascii)
+{
+	try {
+		std::string s{"abc"};
+		std::string r = Utf8::toupper(s);
+
+		ASSERT_EQ("ABC", r);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Toupper8, valid)
+{
+	try {
+		std::string s{"aéc"};
+		std::string r = Utf8::toupper(s);
+
+		ASSERT_EQ("AÉC", r);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Toupper8, invalid)
+{
+	try {
+		std::string s{"a" "\xFF""b"};
+		std::string r = Utf8::toupper(s);
+
+		FAIL() << "expected a failure";
+	} catch (const std::exception &ex) {
+		SUCCEED();
+	}
+}
+
+/* --------------------------------------------------------
+ * UTF8 to lower
+ * -------------------------------------------------------- */
+
+TEST(Tolower8, ascii)
+{
+	try {
+		std::string s{"ABC"};
+		std::string r = Utf8::tolower(s);
+
+		ASSERT_EQ("abc", r);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Tolower8, valid)
+{
+	try {
+		std::string s{"AÉC"};
+		std::string r = Utf8::tolower(s);
+
+		ASSERT_EQ("aéc", r);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+TEST(Tolower8, invalid)
+{
+	try {
+		std::string s{"A" "\xFF""B"};
+		std::string r = Utf8::tolower(s);
+
+		FAIL() << "expected a failure";
+	} catch (const std::exception &ex) {
+		SUCCEED();
+	}
+}
+
+/* --------------------------------------------------------
+ * Check functions
+ * -------------------------------------------------------- */
+
+TEST(Check, isspace)
+{
+	ASSERT_TRUE(Utf8::isspace(' '));
+	ASSERT_FALSE(Utf8::isspace(/* é */ 233));
+}
+
+TEST(Check, isletter)
+{
+	ASSERT_TRUE(Utf8::isletter(/* é */ 233));
+	ASSERT_FALSE(Utf8::isletter(/* € */ 8364));
+}
+
+TEST(Check, isupper)
+{
+	ASSERT_FALSE(Utf8::isupper('a'));
+	ASSERT_FALSE(Utf8::isupper(/* é */ 233));
+	ASSERT_TRUE(Utf8::isupper('A'));
+	ASSERT_TRUE(Utf8::isupper(/* É */ 201));
+}
+
+TEST(Check, islower)
+{
+	ASSERT_TRUE(Utf8::islower('a'));
+	ASSERT_TRUE(Utf8::islower(/* é */ 233));
+	ASSERT_FALSE(Utf8::islower('A'));
+	ASSERT_FALSE(Utf8::islower(/* É */ 201));
+}
+
+/* --------------------------------------------------------
+ * Miscellaneous
+ * -------------------------------------------------------- */
+
+TEST(Misc, nbytesPoint)
+{
+	ASSERT_EQ(1, Utf8::nbytesPoint('a'));
+	ASSERT_EQ(2, Utf8::nbytesPoint(/* é */ 233));
+	ASSERT_EQ(3, Utf8::nbytesPoint(/* € */ 8364));
+	ASSERT_EQ(4, Utf8::nbytesPoint(/* ð €€ */ 131072));
+}
+
+TEST(Misc, nbytesUtf8)
+{
+	std::string s1{"a"};
+	std::string s2{"é"};
+	std::string s3{"€"};
+	std::string s4{"ð €€"};
+
+	ASSERT_EQ(1, Utf8::nbytesUtf8(s1[0]));
+	ASSERT_EQ(2, Utf8::nbytesUtf8(s2[0]));
+	ASSERT_EQ(3, Utf8::nbytesUtf8(s3[0]));
+	ASSERT_EQ(4, Utf8::nbytesUtf8(s4[0]));	
+}
+
+int main(int argc, char **argv)
+{
+	InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Xdg/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,340 @@
+/*
+ * main.cpp -- main test file for XDG
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Xdg.h>
+
+using namespace testing;
+
+namespace {
+
+std::string myhome;
+
+}
+
+TEST(HomeEmpty, config)
+{
+	ASSERT_TRUE(unsetenv("XDG_CONFIG_HOME") == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.config", xdg.configHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeEmpty, data)
+{
+	ASSERT_TRUE(unsetenv("XDG_DATA_HOME") == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.local/share", xdg.dataHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeEmpty, cache)
+{
+	ASSERT_TRUE(unsetenv("XDG_CACHE_HOME") == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.cache", xdg.cacheHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeEmpty, runtime)
+{
+	ASSERT_TRUE(unsetenv("XDG_RUNTIME_DIR") == 0);
+
+	try {
+		Xdg xdg;
+
+		try {
+			xdg.runtimeDir();
+
+			ASSERT_TRUE(false);
+		} catch (const std::exception &) { }
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_HOME", "/test/config", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/config", xdg.configHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_HOME", "/test/data", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/data", xdg.dataHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, cache)
+{
+	ASSERT_TRUE(setenv("XDG_CACHE_HOME", "/test/cache", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/cache", xdg.cacheHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, runtime)
+{
+	ASSERT_TRUE(setenv("XDG_RUNTIME_DIR", "/test/runtime", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/runtime", xdg.runtimeDir());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_HOME", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.config", xdg.configHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_HOME", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.local/share", xdg.dataHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, cache)
+{
+	ASSERT_TRUE(setenv("XDG_CACHE_HOME", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.cache", xdg.cacheHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, runtime)
+{
+	ASSERT_TRUE(setenv("XDG_RUNTIME_DIR", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		try {
+			xdg.runtimeDir();
+
+			ASSERT_TRUE(false);
+		} catch (const std::exception &) { }
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesEmpty, config)
+{
+	ASSERT_TRUE(unsetenv("XDG_CONFIG_DIRS") == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)1, list.size());
+		ASSERT_EQ("/etc/xdg", list[0]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesEmpty, data)
+{
+	ASSERT_TRUE(unsetenv("XDG_DATA_DIRS") == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/usr/local/share", list[0]);
+		ASSERT_EQ("/usr/share", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesValid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "/config1:/config2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/config1", list[0]);
+		ASSERT_EQ("/config2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesValid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "/data1:/data2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/data1", list[0]);
+		ASSERT_EQ("/data2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesInvalid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "bad1:bad2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)1, list.size());
+		ASSERT_EQ("/etc/xdg", list[0]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesInvalid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "bad1:bad2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/usr/local/share", list[0]);
+		ASSERT_EQ("/usr/share", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesMixed, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "/config1:bad:/config2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/config1", list[0]);
+		ASSERT_EQ("/config2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesMixed, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "/data1:bad:/data2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/data1", list[0]);
+		ASSERT_EQ("/data2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	auto home = getenv("HOME");
+
+	if (home == nullptr)
+		return 0;
+
+	myhome = home;
+	InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Zip/data/data.txt	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,1 @@
+abcdef
Binary file C++/tests/Zip/data/stats.zip has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/tests/Zip/main.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,270 @@
+/*
+ * main.cpp -- test the zip wrapper functions
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <ZipArchive.h>
+
+using namespace source;
+
+/* --------------------------------------------------------
+ * Sources
+ * -------------------------------------------------------- */
+
+TEST(Source, file)
+{
+	remove("output.zip");
+
+	try {
+		ZipArchive archive("output.zip", ZIP_CREATE);
+
+		archive.add(File("Zip/data.txt"), "data.txt");
+	} catch (const std::exception &ex) {
+		std::cerr << ex.what() << std::endl;
+	}
+
+	try {
+		ZipArchive archive("output.zip");
+
+		auto stats = archive.stat("data.txt");
+		auto file = archive.open("data.txt");
+		auto content = file.read(stats.size);
+
+		ASSERT_EQ("abcdef\n", content);
+	} catch (const std::exception &ex) {
+		std::cerr << ex.what() << std::endl;
+	}
+}
+
+TEST(Source, buffer)
+{
+	remove("output.zip");
+
+	try {
+		ZipArchive archive{"output.zip", ZIP_CREATE};
+
+		archive.add(Buffer{"abcdef"}, "data.txt");
+	} catch (const std::exception &ex) {
+		std::cerr << ex.what() << std::endl;
+	}
+
+	try {
+		ZipArchive archive{"output.zip"};
+
+		auto stats = archive.stat("data.txt");
+		auto file = archive.open("data.txt");
+		auto content = file.read(stats.size);
+
+		ASSERT_EQ("abcdef", content);
+	} catch (const std::exception &ex) {
+		std::cerr << ex.what() << std::endl;
+	}
+}
+
+/* --------------------------------------------------------
+ * Write
+ * -------------------------------------------------------- */
+
+TEST(Write, simple)
+{
+	remove("output.zip");
+
+	// Open first and save some data
+	try {
+		ZipArchive archive("output.zip", ZIP_CREATE);
+
+		archive.add(Buffer("hello world!"), "DATA");
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+
+	try {
+		ZipArchive archive("output.zip");
+
+		auto stats = archive.stat("DATA");
+		auto file = archive.open("DATA");
+		auto content = file.read(stats.size);
+
+		ASSERT_EQ(static_cast<decltype(stats.size)>(12), stats.size);
+		ASSERT_EQ("hello world!", content);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+/* --------------------------------------------------------
+ * Reading
+ * -------------------------------------------------------- */
+
+class ReadingTest : public testing::Test {
+protected:
+	ZipArchive m_archive;
+
+public:
+	ReadingTest()
+		: m_archive("Zip/stats.zip")
+	{
+	}
+};
+
+TEST_F(ReadingTest, numEntries)
+{
+	ASSERT_EQ(static_cast<ZipInt64>(4), m_archive.numEntries());
+}
+
+TEST_F(ReadingTest, stat)
+{
+	try {
+		ZipStat stats = m_archive.stat("README");
+
+		ASSERT_EQ(static_cast<decltype(stats.size)>(15), stats.size);
+		ASSERT_STREQ("README", stats.name);
+	} catch (const std::exception &ex) {
+		std::cerr << ex.what() << std::endl;
+	}
+}
+
+TEST_F(ReadingTest, read)
+{
+	try {
+		auto file = m_archive.open("README");
+		auto stats = m_archive.stat("README");
+		auto text = file.read(stats.size);
+
+		ASSERT_EQ("This is a test\n", text);
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
+}
+
+TEST_F(ReadingTest, increment)
+{
+	{
+		ZipArchive::iterator it = m_archive.begin();
+
+		ASSERT_STREQ("README", (*it++).name);
+	}
+
+	{
+		ZipArchive::iterator it = m_archive.begin();
+
+		ASSERT_STREQ("INSTALL", (*++it).name);
+	}
+
+	{
+		ZipArchive::iterator it = m_archive.begin() + 1;
+
+		ASSERT_STREQ("INSTALL", (*it).name);
+	}
+}
+
+TEST_F(ReadingTest, decrement)
+{
+	{
+		ZipArchive::iterator it = m_archive.begin() + 1;
+
+		ASSERT_STREQ("INSTALL", (*it--).name);
+	}
+
+	{
+		ZipArchive::iterator it = m_archive.begin() + 1;
+
+		ASSERT_STREQ("README", (*--it).name);
+	}
+
+	{
+		ZipArchive::iterator it = m_archive.end() - 1;
+
+		ASSERT_STREQ("doc/REFMAN", (*it).name);
+	}
+}
+
+TEST_F(ReadingTest, constIncrement)
+{
+	{
+		ZipArchive::const_iterator it = m_archive.cbegin();
+
+		ASSERT_STREQ("README", (*it++).name);
+	}
+
+	{
+		ZipArchive::const_iterator it = m_archive.cbegin();
+
+		ASSERT_STREQ("INSTALL", (*++it).name);
+	}
+
+	{
+		ZipArchive::const_iterator it = m_archive.cbegin() + 1;
+
+		ASSERT_STREQ("INSTALL", (*it).name);
+	}
+}
+
+TEST_F(ReadingTest, constDecrement)
+{
+	{
+		ZipArchive::const_iterator it = m_archive.cbegin() + 1;
+
+		ASSERT_STREQ("INSTALL", (*it--).name);
+	}
+
+	{
+		ZipArchive::const_iterator it = m_archive.cbegin() + 1;
+
+		ASSERT_STREQ("README", (*--it).name);
+	}
+
+	{
+		ZipArchive::const_iterator it = m_archive.cend() - 1;
+
+		ASSERT_STREQ("doc/REFMAN", (*it).name);
+	}
+}
+
+TEST_F(ReadingTest, access)
+{
+	{
+		ZipArchive::iterator it = m_archive.begin();
+
+		ASSERT_STREQ("README", it->name);
+		ASSERT_STREQ("INSTALL", it[1].name);
+	}
+
+	{
+		ZipArchive::const_iterator it = m_archive.cbegin();
+
+		ASSERT_STREQ("README", it->name);
+		ASSERT_STREQ("INSTALL", it[1].name);
+	}
+}
+
+TEST_F(ReadingTest, loop)
+{
+	std::vector<std::string> names{"README", "INSTALL", "doc/", "doc/REFMAN"};
+	int i = 0;
+
+	for (const ZipStat &s : m_archive)
+		ASSERT_STREQ(names[i++].c_str(), s.name);
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/asprintf.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,129 @@
+/*
+ * asprintf.c -- basic port of asprintf / vsprintf functions
+ *
+ * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+/*
+ * The Microsoft implementation relies on the Win32 API function
+ * _vscprintf which count the number of characters needed. Otherwise the C99
+ * function vsnprintf returns the number of character that would be printed.
+ *
+ * Finally, if we don't have C99, we use an optimistic function.
+ *
+ * The asprintf function is common to every implementations.
+ */
+
+#if defined(_MSC_VER)
+
+/*
+ * Windows implementation.
+ */
+int
+vasprintf(char **res, const char *fmt, va_list ap)
+{
+	int total = _vscprintf(fmt, ap);
+
+	if (total < 0) {
+		*res = NULL;
+		return -1;
+	}
+
+	if ((*res = (char *)malloc(sizeof (total) + 1)) == NULL)
+		return -1;
+
+	return vsprintf_s(*res, total + 1, fmt, ap);
+}
+
+#elif __STDC_VERSION__ >= 199901L
+
+/*
+ * C99 implementation using vsnprintf's return value.
+ */
+int
+vasprintf(char **res, const char *fmt, va_list ap)
+{
+	int total, nwritten;
+	va_list copy;
+
+	va_copy(copy, ap);
+	total = vsnprintf(NULL, 0, fmt, copy);
+	va_end(copy);
+
+	if (total < 0) {
+		*res = NULL;
+		return total;
+	}
+
+	if ((*res = malloc(total + 1)) == NULL)
+		return -1;
+
+	if ((nwritten = vsnprintf(*res, total + 1, fmt, ap)) < 0) {
+		free(*res);
+		*res = NULL;
+
+		return -1;
+	}
+
+	return nwritten;
+}
+
+#else
+
+/*
+ * Optimistic function fallback.
+ */
+int
+vasprintf(char **res, const char *format, va_list ap)
+{
+	int rvalue, ok;
+	size_t base = 80;
+
+	if ((*res = malloc(base)) == NULL)
+		return -1;
+
+	ok = 0;
+	do {
+		rvalue = vsnprintf(*res, base, format, ap);
+
+		if ((signed int)base <= rvalue || rvalue < 0) {
+			*res = realloc(*res, base * 2);
+			base *= 2;
+		} else
+			ok = 1;
+	} while (!ok && *res != NULL);
+
+	return rvalue;
+}
+
+#endif
+
+int
+asprintf(char **res, const char *fmt, ...)
+{
+	va_list ap;
+	int rvalue;
+
+	va_start(ap, fmt);
+	rvalue = vasprintf(res, fmt, ap);
+	va_end(ap);
+
+	return rvalue;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/asprintf.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,36 @@
+/*
+ * asprintf.h -- basic port of asprintf / vsprintf functions
+ *
+ * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#  define _asp_at_printf(i1, i2)	__attribute__ ((format (printf, i1, i2)))
+#else
+#  define _asp_at_printf(i1, i2)
+#endif
+
+int	asprintf(char **, const char *, ...) _asp_at_printf(2, 3);
+int	vasprintf(char **, const char *, va_list);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/err.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,114 @@
+/*
+ * err.c -- formtted error messages (portable version)
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "err.h"
+
+/*
+ * These functions implements at least the same functions that can be found
+ * in the NetBSD err(3) man page without printing the programe name due to
+ * a portability issue.
+ */
+
+void
+err(int val, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	verr(val, fmt, ap);
+	va_end(ap);
+}
+
+void
+verr(int val, const char *fmt, va_list ap)
+{
+	if (fmt) {
+		vfprintf(stderr, fmt, ap);
+		fprintf(stderr, ": ");
+	}
+
+	fprintf(stderr, "%s\n", strerror(errno));
+	exit(val);
+}
+
+void
+errx(int val, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	verrx(val, fmt, ap);
+	va_end(ap);
+}
+
+void
+verrx(int val, const char *fmt, va_list ap)
+{
+	if (fmt)
+		vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+
+	exit(val);
+}
+
+void
+warn(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vwarn(fmt, ap);
+	va_end(ap);
+}
+
+void
+vwarn(const char *fmt, va_list ap)
+{
+	if (fmt) {
+		vfprintf(stderr, fmt, ap);
+		fprintf(stderr, ": ");
+	}
+
+	fprintf(stderr, "%s\n", strerror(errno));
+}
+
+void
+warnx(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vwarnx(fmt, ap);
+	va_end(ap);
+}
+
+void
+vwarnx(const char *fmt, va_list ap)
+{
+	if (fmt)
+		vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/err.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * err.h -- formtted error messages (portable version)
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ERR_H_
+#define _ERR_H_
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Attribute noreturn may helps. This may produce a warning with GCC 4.5:
+ *
+ * int a;
+ *
+ * if ((a = getstate() < 0)
+ *	errx(1, "State failed");
+ *
+ * Because compilator does not know that errx will call exit may produce
+ * a warning like `a may be used uninitialized'.
+ */
+
+#if defined(__GNUC__)
+#  define __at_noreturn	__attribute__ ((noreturn))
+#elif defined(_MSC_VER)
+#  define __at_noreturn	__declspec(noreturn)
+#endif
+
+/*
+ * err() functions append the format message to the stderr FILE pointer. They
+ * also append the system error using strerror(errno). Then the functions exit
+ * with the error code given as first argument.
+ */
+
+void	err(int, const char *, ...) __at_noreturn;
+void	verr(int, const char *, va_list) __at_noreturn;
+
+/*
+ * errx() functions are similar to err() except that they do not append the
+ * system error message.
+ */
+
+void	errx(int, const char *, ...) __at_noreturn;
+void	verrx(int, const char *, va_list) __at_noreturn;
+
+/*
+ * warn() functions are similar to err() but they do not call exit().
+ */
+
+void	warn(const char *, ...);
+void	vwarn(const char *, va_list);
+
+/*
+ * warnx() functions are similar to warn() except that they do not append the
+ * system error message.
+ */
+
+void	warnx(const char *, ...);
+void	vwarnx(const char *, va_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ERR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/extern/getopt.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,124 @@
+/*
+ * getopt.c -- getopt(3) from FreeBSD (portable version)
+ */
+
+/*-
+ * Copyright (c) 1987, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int	opterr = 1,		/* if error message should be printed */
+	optind = 1,		/* index into parent argv vector */
+	optopt,			/* character checked for validity */
+	optreset;		/* reset getopt */
+char	*optarg;		/* argument associated with option */
+
+#define	BADCH	(int)'?'
+#define	BADARG	(int)':'
+#define	EMSG	""
+
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+	int nargc;
+	char * const nargv[];
+	const char *ostr;
+{
+	static char *place = EMSG;		/* option letter processing */
+	char *oli;				/* option letter list index */
+
+	if (optreset || *place == 0) {		/* update scanning pointer */
+		optreset = 0;
+		place = nargv[optind];
+		if (optind >= nargc || *place++ != '-') {
+			/* Argument is absent or is not an option */
+			place = EMSG;
+			return (-1);
+		}
+		optopt = *place++;
+		if (optopt == '-' && *place == 0) {
+			/* "--" => end of options */
+			++optind;
+			place = EMSG;
+			return (-1);
+		}
+		if (optopt == 0) {
+			/* Solitary '-', treat as a '-' option
+			   if the program (eg su) is looking for it. */
+			place = EMSG;
+			if (strchr(ostr, '-') == NULL)
+				return (-1);
+			optopt = '-';
+		}
+	} else
+		optopt = *place++;
+
+	/* See if option letter is one the caller wanted... */
+	if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
+		if (*place == 0)
+			++optind;
+		if (opterr && *ostr != ':')
+			(void)fprintf(stderr,
+			    "illegal option -- %c\n", optopt);
+		return (BADCH);
+	}
+
+	/* Does this option need an argument? */
+	if (oli[1] != ':') {
+		/* don't need argument */
+		optarg = NULL;
+		if (*place == 0)
+			++optind;
+	} else {
+		/* Option-argument is either the rest of this argument or the
+		   entire next argument. */
+		if (*place)
+			optarg = place;
+		else if (nargc > ++optind)
+			optarg = nargv[optind];
+		else {
+			/* option-argument absent */
+			place = EMSG;
+			if (*ostr == ':')
+				return (BADARG);
+			if (opterr)
+				(void)fprintf(stderr,
+				    "option requires an argument -- %c\n", optopt);
+			return (BADCH);
+		}
+		place = EMSG;
+		++optind;
+	}
+	return (optopt);			/* return option letter */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/extern/getopt.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * getopt.h -- getopt(3) from FreeBSD (portable version)
+ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+int getopt(int, char * const [], const char *);
+
+extern char *optarg;			/* getopt(3) external variables */
+extern int optind, opterr, optopt;
+extern int optreset;			/* getopt(3) external variable */
+
+#endif /* !_GETOPT_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/extern/queue.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,584 @@
+/*
+ * queue.h -- queue(3) from FreeBSD (portable version)
+ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.72.2.4 2011/05/24 16:04:35 mdf Exp $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *				SLIST	LIST	STAILQ	TAILQ
+ * _HEAD			+	+	+	+
+ * _HEAD_INITIALIZER		+	+	+	+
+ * _ENTRY			+	+	+	+
+ * _INIT			+	+	+	+
+ * _EMPTY			+	+	+	+
+ * _FIRST			+	+	+	+
+ * _NEXT			+	+	+	+
+ * _PREV			-	-	-	+
+ * _LAST			-	-	+	+
+ * _FOREACH			+	+	+	+
+ * _FOREACH_SAFE		+	+	+	+
+ * _FOREACH_REVERSE		-	-	-	+
+ * _FOREACH_REVERSE_SAFE	-	-	-	+
+ * _INSERT_HEAD			+	+	+	+
+ * _INSERT_BEFORE		-	+	-	+
+ * _INSERT_AFTER		+	+	+	+
+ * _INSERT_TAIL			-	-	+	+
+ * _CONCAT			-	-	+	+
+ * _REMOVE_AFTER		+	-	+	-
+ * _REMOVE_HEAD			+	-	+	-
+ * _REMOVE			+	+	+	+
+ * _SWAP			+	+	+	+
+ *
+ */
+
+/*
+ * winnt.h includes some variables like SLIST_ENTRY, so undef all. If this
+ * file is used it is probably because the user want is instead of
+ * windows ones.
+ */
+
+#undef SLIST_EMPTY
+#undef SLIST_ENTRY
+#undef SLIST_FIRST
+#undef SLIST_FOREACH
+#undef SLIST_FOREACH_SAFE
+#undef SLIST_HEAD
+#undef SLIST_HEAD_INITIALIZER
+#undef SLIST_INIT
+#undef SLIST_INSERT_AFTER
+#undef SLIST_INSERT_HEAD
+#undef SLIST_NEXT
+#undef SLIST_REMOVE_AFTER
+#undef SLIST_REMOVE_HEAD
+#undef SLIST_REMOVE
+#undef SLIST_SWAP
+#undef STAILQ_CONCAT
+#undef STAILQ_EMPTY
+#undef STAILQ_ENTRY
+#undef STAILQ_FIRST
+#undef STAILQ_FOREACH
+#undef STAILQ_FOREACH_SAFE
+#undef STAILQ_HEAD
+#undef STAILQ_HEAD_INITIALIZER
+#undef STAILQ_INIT
+#undef STAILQ_INSERT_AFTER
+#undef STAILQ_INSERT_HEAD
+#undef STAILQ_INSERT_TAIL
+#undef STAILQ_LAST
+#undef STAILQ_NEXT
+#undef STAILQ_REMOVE_AFTER
+#undef STAILQ_REMOVE_HEAD
+#undef STAILQ_REMOVE
+#undef STAILQ_SWAP
+#undef LIST_EMPTY
+#undef LIST_ENTRY
+#undef LIST_FIRST
+#undef LIST_FOREACH
+#undef LIST_FOREACH_SAFE
+#undef LIST_HEAD
+#undef LIST_HEAD_INITIALIZER
+#undef LIST_INIT
+#undef LIST_INSERT_AFTER
+#undef LIST_INSERT_BEFORE
+#undef LIST_INSERT_HEAD
+#undef LIST_NEXT
+#undef LIST_REMOVE
+#undef LIST_SWAP
+#undef TAILQ_CONCAT
+#undef TAILQ_EMPTY
+#undef TAILQ_ENTRY
+#undef TAILQ_FIRST
+#undef TAILQ_FOREACH
+#undef TAILQ_FOREACH_SAFE
+#undef TAILQ_FOREACH_REVERSE
+#undef TAILQ_FOREACH_REVERSE_SAFE
+#undef TAILQ_HEAD
+#undef TAILQ_HEAD_INITIALIZER
+#undef TAILQ_INIT
+#undef TAILQ_INSERT_AFTER
+#undef TAILQ_INSERT_BEFORE
+#undef TAILQ_INSERT_HEAD
+#undef TAILQ_INSERT_TAIL
+#undef TAILQ_LAST
+#undef TAILQ_NEXT
+#undef TAILQ_PREV
+#undef TAILQ_REMOVE
+#undef TAILQ_SWAP
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
+	for ((varp) = &SLIST_FIRST((head));				\
+	    ((var) = *(varp)) != NULL;					\
+	    (varp) = &SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_REMOVE_AFTER(curelm, field);			\
+	}								\
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do {				\
+	SLIST_NEXT(elm, field) =					\
+	    SLIST_NEXT(SLIST_NEXT(elm, field), field);			\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
+#define SLIST_SWAP(head1, head2, type) do {				\
+	struct type *swap_first = SLIST_FIRST(head1);			\
+	SLIST_FIRST(head1) = SLIST_FIRST(head2);			\
+	SLIST_FIRST(head2) = swap_first;				\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+
+#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = STAILQ_FIRST((head));				\
+	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY((head)) ?						\
+		NULL :							\
+	        ((struct type *)(void *)				\
+		((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		STAILQ_REMOVE_AFTER(head, curelm, field);		\
+	}								\
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do {			\
+	if ((STAILQ_NEXT(elm, field) =					\
+	     STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define STAILQ_SWAP(head1, head2, type) do {				\
+	struct type *swap_first = STAILQ_FIRST(head1);			\
+	struct type **swap_last = (head1)->stqh_last;			\
+	STAILQ_FIRST(head1) = STAILQ_FIRST(head2);			\
+	(head1)->stqh_last = (head2)->stqh_last;			\
+	STAILQ_FIRST(head2) = swap_first;				\
+	(head2)->stqh_last = swap_last;					\
+	if (STAILQ_EMPTY(head1))					\
+		(head1)->stqh_last = &STAILQ_FIRST(head1);		\
+	if (STAILQ_EMPTY(head2))					\
+		(head2)->stqh_last = &STAILQ_FIRST(head2);		\
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = LIST_FIRST((head));				\
+	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+} while (0)
+
+#define LIST_SWAP(head1, head2, type, field) do {			\
+	struct type *swap_tmp = LIST_FIRST((head1));			\
+	LIST_FIRST((head1)) = LIST_FIRST((head2));			\
+	LIST_FIRST((head2)) = swap_tmp;					\
+	if ((swap_tmp = LIST_FIRST((head1))) != NULL)			\
+		swap_tmp->field.le_prev = &LIST_FIRST((head1));		\
+	if ((swap_tmp = LIST_FIRST((head2))) != NULL)			\
+		swap_tmp->field.le_prev = &LIST_FIRST((head2));		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue functions.
+ */
+
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
+	    (var) = (tvar))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else {								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	}								\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else {								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	}								\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define TAILQ_SWAP(head1, head2, type, field) do {			\
+	struct type *swap_first = (head1)->tqh_first;			\
+	struct type **swap_last = (head1)->tqh_last;			\
+	(head1)->tqh_first = (head2)->tqh_first;			\
+	(head1)->tqh_last = (head2)->tqh_last;				\
+	(head2)->tqh_first = swap_first;				\
+	(head2)->tqh_last = swap_last;					\
+	if ((swap_first = (head1)->tqh_first) != NULL)			\
+		swap_first->field.tqe_prev = &(head1)->tqh_first;	\
+	else								\
+		(head1)->tqh_last = &(head1)->tqh_first;		\
+	if ((swap_first = (head2)->tqh_first) != NULL)			\
+		swap_first->field.tqe_prev = &(head2)->tqh_first;	\
+	else								\
+		(head2)->tqh_last = &(head2)->tqh_first;		\
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/extern/stdbool.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000 Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/include/stdbool.h,v 1.7.28.1.2.1 2011/11/11 04:20:22 kensmith Exp $
+ */
+
+#ifndef _STDBOOL_H_
+#define	_STDBOOL_H_	
+
+#define	__bool_true_false_are_defined	1
+
+#ifndef __cplusplus
+
+#define	false	0
+#define	true	1
+
+/* Very portable bool version */
+typedef	char	bool;
+
+#endif /* !__cplusplus */
+
+#endif /* !_STDBOOL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/extern/strlcat.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2012 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stddef.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end */
+	while (n-- != 0 && *d != '\0')
+		d++;
+	dlen = d - dst;
+	n = siz - dlen;
+
+	if (n == 0)
+		return(dlen + strlen(s));
+	while (*s != '\0') {
+		if (n != 1) {
+			*d++ = *s;
+			n--;
+		}
+		s++;
+	}
+	*d = '\0';
+
+	return(dlen + (s - src));	/* count does not include NUL */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/extern/strlcpy.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2012 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stddef.h>
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0) {
+		while (--n != 0) {
+			if ((*d++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/setprogname.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,45 @@
+/*
+ * setprogname.c -- get or set the program name
+ *
+ * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Do not return NULL if the developer didn't call setprogname to
+ * prevent useless segfault.
+ */
+static const char	*g_pname = "";
+
+void
+setprogname(const char *progname)
+{
+	const char *p;
+
+	/* Seek last / or \ on windows */
+	if ((p = strrchr(progname, '/')) || (p = strrchr(progname, '\\')))
+		g_pname = &p[1];
+	else
+		g_pname = progname;
+}
+
+const char *
+getprogname(void)
+{
+	return g_pname;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/setprogname.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,28 @@
+/*
+ * setprogname.h -- get or set the program name
+ *
+ * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void		setprogname(const char *);
+const char	*getprogname(void);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/strdup.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,35 @@
+/*
+ * strdup.c -- duplicate a string
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+strdup(const char *src)
+{
+	char *dst;
+	size_t len;
+
+	len = strlen(src);
+
+	if ((dst = calloc(len + 1, sizeof (char))) == NULL)
+		return NULL;
+
+	return strcpy(dst, src);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/strdup.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,28 @@
+/*
+ * strdup.h -- duplicate a string
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char	*strdup(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/strndup.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,36 @@
+/*
+ * strndup.c -- duplicate a string
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+strndup(const char *src, size_t len)
+{
+	size_t tocopy;
+	char *dst;
+
+	for (tocopy = 0; tocopy < len && src[tocopy] != '\0'; ++tocopy)
+		continue;
+
+	if ((dst = calloc(tocopy + 1, 1)) != NULL)
+		strncpy(dst, src, tocopy);
+
+	return dst;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/strndup.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,27 @@
+/*
+ * strndup.h -- duplicate a string
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char	*strndup(const char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/strsep.c	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,40 @@
+/*
+ * strsep.c -- separate a string by delimiters
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+char *
+strsep(char **stringp, const char *delim)
+{
+	char *item, *ptr;
+
+	if (*stringp == NULL || delim[0] == '\0')
+		return NULL;
+
+	item = *stringp;	
+	if ((ptr = strpbrk(*stringp, delim)) == NULL) {
+		*stringp = NULL;
+		return item;
+	}
+
+	*ptr = '\0';
+	*stringp = ptr + 1;
+
+	return item;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/port/strsep.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,27 @@
+/*
+ * strsep.h -- separate a string by delimiters
+ *
+ * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char	*strsep(char **, const char *);
+
+#ifdef __cplusplus
+}
+#endif
--- a/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ b/CMakeLists.txt	Sun Mar 08 14:26:33 2015 +0100
@@ -25,103 +25,372 @@
 
 set(CMAKE_MODULE_PATH ${code_SOURCE_DIR}/cmake)
 
+include(CMakeParseArguments)
+
+add_subdirectory(extern)
+add_subdirectory(tools)
+
 enable_testing()
 
-include_directories(
-	${code_SOURCE_DIR}/C++
+macro(define_module)
+	set(oneValueArgs TARGET NAME DIRECTORY)
+	set(multiValueArgs SOURCES RESOURCES DOCS LIBRARIES INCLUDES)
+
+	cmake_parse_arguments(MOD "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+	if (NOT MOD_TARGET)
+		message(FATAL_ERROR "Argument TARGET not set")
+	elseif (NOT MOD_NAME)
+		message(FATAL_ERROR "Argument NAME not set")
+	elseif (NOT MOD_DIRECTORY)
+		message(FATAL_ERROR "Argument DIRECTORY not set")
+	endif ()
+
+	string(TOUPPER ${MOD_NAME} optionname)
+
+	# Create the option for enabling the test
+	option(WITH_${optionname} "Enable ${MOD_NAME}" On)
+
+	if (WITH_${optionname})
+		# Add the test executable
+		set(MAIN ${code_SOURCE_DIR}/C++/tests/${MOD_DIRECTORY}/main.cpp)
+
+		if (NOT EXISTS ${MAIN})
+			message(FATAL_ERROR "${MAIN} file does not exists")
+		endif ()
+
+		add_executable(${MOD_TARGET} ${MOD_SOURCES} ${MOD_RESOURCES} ${MOD_DOCS} ${MAIN})
+		add_test(${MOD_TARGET}-test ${MOD_TARGET})
+		target_include_directories(
+			${MOD_TARGET}
+			PRIVATE
+				${code_SOURCE_DIR}/C++
+				${code_SOURCE_DIR}/C++/modules/${MOD_DIRECTORY}
+				${MOD_INCLUDES}
+		)
+		target_link_libraries(${MOD_TARGET} gtest ${MOD_LIBRARIES})
+
+		# Copy optional resources
+		if (MOD_RESOURCES)
+			foreach (res ${MOD_RESOURCES})
+				get_filename_component(inputname ${res} NAME)
+				set(output ${CMAKE_BINARY_DIR}/${MOD_DIRECTORY}/${inputname})
+				list(APPEND outputlist ${output})
+
+				add_custom_command(
+					OUTPUT ${output}
+					COMMENT "Copying ${inputname}"
+					DEPENDS ${res}
+					COMMAND ${CMAKE_COMMAND} -E copy ${res} ${output}
+				)
+			endforeach()
+
+			add_custom_target(${MOD_TARGET}-resources DEPENDS ${outputlist})
+			add_dependencies(${MOD_TARGET} ${MOD_TARGET}-resources)
+		endif ()
+
+		# Generate documentation locally
+		if (MOD_DOCS)
+			foreach (doc ${MOD_DOCS})
+				file(RELATIVE_PATH inputbase ${code_SOURCE_DIR}/C++/doc/${MOD_DIRECTORY} ${doc})
+				string(REGEX REPLACE "^(.*)\\.md" "\\1.html" outputname ${inputbase})
+				set(output ${CMAKE_BINARY_DIR}/doc/${MOD_DIRECTORY}/${outputname})
+
+				pandoc(
+					SOURCES ${doc}
+					OUTPUT ${output}
+					FROM markdown TO html5
+					MAKE_DIRECTORY STANDALONE
+					FILTER $<TARGET_FILE:mdtohtml>
+				)
+
+				list(APPEND docoutputlist ${output})
+			endforeach ()
+
+			add_custom_target(${MOD_TARGET}-doc DEPENDS ${docoutputlist})
+			add_dependencies(${MOD_TARGET} ${MOD_TARGET}-doc)
+		endif ()
+	endif ()
+endmacro()
+
+find_package(Pandoc REQUIRED)
+find_package(OpenSSL REQUIRED)
+find_package(Jansson REQUIRED)
+
+# ---------------------------------------------------------
+# Base64
+# ---------------------------------------------------------
+
+define_module(
+	TARGET base64
+	NAME Base64
+	DIRECTORY Base64
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Base64/Base64.cpp
+		${code_SOURCE_DIR}/C++/modules/Base64/Base64.h
 )
 
-# GoogleTest library
-add_subdirectory(extern)
+# ---------------------------------------------------------
+# Converter
+# ---------------------------------------------------------
+
+# No tests yet
 
-function(define_test name sources)
-	# The executable
-	add_executable(
-		${name}
-		${sources}
-	)
+# ---------------------------------------------------------
+# Directory
+# ---------------------------------------------------------
 
-	target_link_libraries(${name} gtest)
-	add_test(${name}-test ${name})
-endfunction()
+define_module(
+	TARGET directory
+	NAME Directory
+	DIRECTORY Directory
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Directory/Directory.cpp
+		${code_SOURCE_DIR}/C++/modules/Directory/Directory.h
+)
 
-option(WITH_BASE64 "Enable base64 tests" On)
-option(WITH_CONVERTER "Enable converter tests" On)
-option(WITH_DIRECTORY "Enable directory tests" On)
-option(WITH_DRIVER "Enable SQL drivers tests" On)
-option(WITH_DYNLIB "Enable DynLib tests" On)
-option(WITH_FLAGS "Enable Flags tests" On)
-option(WITH_HASH "Enable hash functions tests" On)
-option(WITH_INI "Enable .ini parser" On)
-option(WITH_JSON "Enable Jansson wrapper tests" On)
-option(WITH_OPTIONPARSER "Enable option parser tests" On)
-option(WITH_PACK "Enable pack functions" On)
-option(WITH_PARSER "Enable parser tests (deprecated)" On)
-option(WITH_SOCKETS "Enable sockets tests" On)
-option(WITH_TREENODE "Enable treenode tests" On)
-option(WITH_UTF8 "Enable Utf8 functions tests" On)
-option(WITH_ZIP "Enable ZipArchive tests" On)
+# ---------------------------------------------------------
+# Driver
+# ---------------------------------------------------------
+
+# No tests yet
 
-if (UNIX)
-	option(WITH_XDG "Enable XDG standard directories tests" On)
+# ---------------------------------------------------------
+# Dynlib
+# ---------------------------------------------------------
+
+if (WIN32)
+	set(EXTENSION ".dll")
+elseif (UNIX)
+	set(EXTENSION ".so")
+elseif (APPLE)
+	set(EXTENSION ".dylib")
+else ()
+	message(FATAL_ERROR "Unsupported platform")
 endif ()
 
-if (WITH_BASE64)
-	add_subdirectory(C++/Tests/Base64)
-endif ()
+define_module(
+	TARGET dynlib
+	NAME Dynlib
+	DIRECTORY Dynlib
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Dynlib/Dynlib.cpp
+		${code_SOURCE_DIR}/C++/modules/Dynlib/Dynlib.h
+	DOCS
+		${code_SOURCE_DIR}/C++/doc/Dynlib/Home.md
+		${code_SOURCE_DIR}/C++/doc/Dynlib/class/Dynlib.md
+		${code_SOURCE_DIR}/C++/doc/Dynlib/class/Dynlib/Constructor.md
+		${code_SOURCE_DIR}/C++/doc/Dynlib/class/Dynlib/Destructor.md
+		${code_SOURCE_DIR}/C++/doc/Dynlib/class/Dynlib/Policy.md
+		${code_SOURCE_DIR}/C++/doc/Dynlib/class/Dynlib/sym.md
+		${code_SOURCE_DIR}/C++/doc/Dynlib/macro/DYNLIB_EXPORT.md
+)
 
-if (WITH_DIRECTORY)
-	add_subdirectory(C++/Tests/Directory)
+if (CMAKE_SYSTEM_NAME MATCHES "Linux")
+	target_link_libraries(dynlib dl)
 endif ()
 
-if (WITH_DYNLIB)
-	add_subdirectory(C++/Tests/DynLib)
-endif ()
+target_compile_definitions(dynlib PRIVATE EXTENSION=\"${EXTENSION}\")
+
+add_library(dynlib-plugin MODULE ${code_SOURCE_DIR}/C++/tests/Dynlib/Plugin.cpp)
+set_target_properties(dynlib-plugin PROPERTIES PREFIX "")
+target_include_directories(dynlib-plugin PRIVATE ${code_SOURCE_DIR}/C++/modules/Dynlib)
+
+# ---------------------------------------------------------
+# Flags
+# ---------------------------------------------------------
+
+define_module(
+	TARGET flags
+	NAME Flags
+	DIRECTORY Flags
+	SOURCES ${code_SOURCE_DIR}/C++/modules/Flags/Flags.h
+)
+
+# ---------------------------------------------------------
+# Hash
+# ---------------------------------------------------------
+
+define_module(
+	TARGET hash
+	NAME Hash
+	DIRECTORY Hash
+	LIBRARIES ${OPENSSL_LIBRARIES}
+	INCLUDES ${OPENSSL_INCLUDE_DIR}
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Hash/Hash.cpp
+		${code_SOURCE_DIR}/C++/modules/Hash/Hash.h
+)
+
+# ---------------------------------------------------------
+# Ini
+# ---------------------------------------------------------
 
-if (WITH_FLAGS)
-	add_subdirectory(C++/Tests/Flags)
-endif ()
+define_module(
+	TARGET ini
+	NAME Ini
+	DIRECTORY Ini
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Ini/Ini.cpp
+		${code_SOURCE_DIR}/C++/modules/Ini/Ini.h
+	RESOURCES
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/compact.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/error-badcomment.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/error-badsection.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/error-lineassigment.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/error-nosection.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/includes.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/multi.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/novalue.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/simple.conf
+		${code_SOURCE_DIR}/C++/tests/Ini/configs/tokens.conf
+)
+
+# ---------------------------------------------------------
+# Json
+# ---------------------------------------------------------
+
+define_module(
+	TARGET json
+	NAME Json
+	DIRECTORY Json
+	INCLUDES ${Jansson_INCLUDES}
+	LIBRARIES ${Jansson_LIBRARIES}
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Json/Json.cpp
+		${code_SOURCE_DIR}/C++/modules/Json/Json.h
+	RESOURCES
+		${code_SOURCE_DIR}/C++/tests/Json/data/array-all.json
+		${code_SOURCE_DIR}/C++/tests/Json/data/array.json
+		${code_SOURCE_DIR}/C++/tests/Json/data/object-all.json
+		${code_SOURCE_DIR}/C++/tests/Json/data/object.json
+		${code_SOURCE_DIR}/C++/tests/Json/data/simple.json
+)
+
+# ---------------------------------------------------------
+# OptionParser
+# ---------------------------------------------------------
+
+define_module(
+	TARGET optionparser
+	NAME OptionParser
+	DIRECTORY OptionParser
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/OptionParser/OptionParser.cpp
+		${code_SOURCE_DIR}/C++/modules/OptionParser/OptionParser.h
+)
 
-if (WITH_HASH)
-	add_subdirectory(C++/Tests/Hash)
-endif ()
+# ---------------------------------------------------------
+# Pack
+# ---------------------------------------------------------
+
+define_module(
+	TARGET pack
+	NAME Pack
+	DIRECTORY Pack
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Pack/Pack.cpp
+		${code_SOURCE_DIR}/C++/modules/Pack/Pack.h
+)
+
+# ---------------------------------------------------------
+# Parser (DEPRECATED)
+# ---------------------------------------------------------
+
+define_module(
+	TARGET parser
+	NAME Parser
+	DIRECTORY Parser
+	RESOURCES
+		${code_SOURCE_DIR}/C++/tests/Parser/configs/simple.conf
+		${code_SOURCE_DIR}/C++/tests/Parser/configs/multi.conf
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Parser/Parser.cpp
+		${code_SOURCE_DIR}/C++/modules/Parser/Parser.h
+)
+
+# ---------------------------------------------------------
+# Sockets
+# ---------------------------------------------------------
 
-if (WITH_JSON)
-	add_subdirectory(C++/Tests/Json)
-endif ()
+define_module(
+	TARGET socket
+	NAME Socket
+	DIRECTORY Socket
+	INCLUDES ${OPENSSL_INCLUDE_DIR}
+	LIBRARIES ${OPENSSL_LIBRARIES}
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketAddress.cpp
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketAddress.h
+		${code_SOURCE_DIR}/C++/modules/Socket/Socket.cpp
+		${code_SOURCE_DIR}/C++/modules/Socket/Socket.h
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketListener.cpp
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketListener.h
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketSsl.cpp
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketSsl.h
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketTcp.cpp
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketTcp.h
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketUdp.cpp
+		${code_SOURCE_DIR}/C++/modules/Socket/SocketUdp.h
+)
+
+# ---------------------------------------------------------
+# Treenode
+# ---------------------------------------------------------
 
-if (WITH_INI)
-	add_subdirectory(C++/Tests/Ini)
-endif ()
+define_module(
+	TARGET treenode
+	NAME Treenode
+	DIRECTORY Treenode
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Treenode/TreeNode.h
+)
+
+# ---------------------------------------------------------
+# Utf8
+# ---------------------------------------------------------
 
-if (WITH_OPTIONPARSER)
-	add_subdirectory(C++/Tests/OptionParser)
+define_module(
+	TARGET utf8
+	NAME Utf8
+	DIRECTORY Utf8
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Utf8/Utf8.cpp
+		${code_SOURCE_DIR}/C++/modules/Utf8/Utf8.h
+)
+
+# ---------------------------------------------------------
+# Xdg
+# ---------------------------------------------------------
+
+if (UNIX)
+	define_module(
+		TARGET xdg
+		NAME Xdg
+		DIRECTORY Xdg
+
+		SOURCES
+			${code_SOURCE_DIR}/C++/modules/Xdg/Xdg.cpp
+			${code_SOURCE_DIR}/C++/modules/Xdg/Xdg.h
+	)
 endif ()
 
-if (WITH_PACK)
-	add_subdirectory(C++/Tests/Pack)
-endif ()
+# ---------------------------------------------------------
+# Zip
+# ---------------------------------------------------------
 
-if (WITH_PARSER)
-	add_subdirectory(C++/Tests/Parser)
-endif ()
-
-if (WITH_SOCKETS)
-	add_subdirectory(C++/Tests/Sockets)
-endif ()
+find_package(ZIP REQUIRED)
 
-if (WITH_TREENODE)
-	add_subdirectory(C++/Tests/TreeNode)
-endif ()
-
-if (WITH_UTF8)
-	add_subdirectory(C++/Tests/Utf8)
-endif ()
-
-if (WITH_XDG AND UNIX)
-	add_subdirectory(C++/Tests/Xdg)
-endif ()
-
-if (WITH_ZIP)
-	add_subdirectory(C++/Tests/Zip)
-endif ()
+define_module(
+	TARGET zip
+	NAME Zip
+	DIRECTORY Zip
+	INCLUDES ${ZIP_INCLUDE_DIRS}
+	LIBRARIES ${ZIP_LIBRARIES}
+	RESOURCES
+		${code_SOURCE_DIR}/C++/tests/Zip/data/data.txt
+		${code_SOURCE_DIR}/C++/tests/Zip/data/stats.zip
+	SOURCES
+		${code_SOURCE_DIR}/C++/modules/Zip/ZipArchive.cpp
+		${code_SOURCE_DIR}/C++/modules/Zip/ZipArchive.h
+)
--- a/cmake/FindCppunit.cmake	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-# Find cppunit, this modules defines:
-# CPPUNIT_INCLUDE_DIR, where to find cppunit/TestCase.h
-# CPPUNIT_LIBRARY, where to find library
-# CPPUNIT_FOUND, if it is found
-
-# find cppunit/TestCase.h
-find_path(
-	CPPUNIT_INCLUDE_DIR cppunit/TestCase.h
-	PATHS
-	/usr/include
-	/usr/local/include
-)
-
-# find libcppunit.so
-find_library(
-	CPPUNIT_LIBRARY NAMES libcppunit cppunit
-	PATHS_SUFFIXES lib lib64
-	PATHS
-	/usr/
-	/usr/local/
-)
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(
-	Cppunit
-	REQUIRED_VARS CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARY
-)
-
-mark_as_advanced(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARY)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/FindPandoc.cmake	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,231 @@
+# FindPandoc
+# ----------
+#
+# Find Pandoc executable, this modules defines:
+#
+# Pandoc_EXECUTABLE, where to find pandoc's executable
+# Pandoc_FOUND, if it is found
+# Pandoc_VERSION, the version
+#
+# This module also defines the following macros:
+#
+# pandoc(
+#	SOURCES file1 [file2 ...]
+#	OUTPUT output
+#	[FROM format]
+#	[TO format]
+#	[TARGET target]
+#	[DEPENDS dependency ...]
+#	[ALL]
+#	[TOC]
+#	[STANDALONE]
+#	[MAKE_DIRECTORY]
+#	[TEMPLATE file]
+#	[FILTER filter]
+#	[HEADER header ...]
+#	[FOOTER footer ...]
+#	[BODY body ...]
+#	[VARIABLE var ...]
+#	[METADATA meta ...]
+#	[ARGS argument ...]
+#	[WORKING_DIRECTORY directory]
+# )
+#
+# The sources files are listed in the parameter SOURCES, all files are passed
+# in the same order they are passed to that variable.
+#
+# The OUTPUT file is set with OUTPUT. It is generated only if one of the file
+# has changed.
+#
+# The FROM (-f) and TO (-t) arguments specify respectively the source and
+# destinations formats.
+#
+# If the parameter TARGET is set, then a target named `target` will be added
+# with the OUTPUT file as the dependency but not listed as sources files.
+# But the SOURCES files will be added as the target sources in the IDE.
+#
+# Optional dependencies can be added to the output command (not the target) with
+# the DEPENDS parameter.
+#
+# If ALL is set and TARGET is also set, the target will be added to the ALL_BUILD.
+#
+# If TOC (--toc) is specified, a table of content will be automatically created.
+#
+# If STANDALONE (-s) is set, the compilation will assume that it is standalone
+# and adds the necessary of the output format.
+#
+# Optional MAKE_DIRECTORY can be set to create the output directory before
+# pandoc processes the file (recommended).
+#
+# The TEMPLATE parameter can be used to specify the formate template file.
+#
+# You can set a filter with the parameter FILTER. The filter will be added to
+# the output dependencies so you can safely use CMake's targets.
+#
+# The HEADER (-H), FOOTER (-A) and BODY (-B) are copied verbatim before, just
+# after and after the body respectively. They can be set more than once.
+#
+# You can pass variables (-V) and metadata (-M) to the parameters VARIABLE
+# and METADATA, be sure to pass the same syntax as pandoc.  (e.g VARIABLE foo=1)
+#
+# ARGS is an optional list of additional arguments to pass to pandoc.
+#
+# The parameter WORKING_DIRECTORY can be set to change the directory when pandoc
+# is invoked.
+#
+
+find_program(
+	Pandoc_EXECUTABLE
+	NAMES pandoc
+	DOC "Pandoc executable"
+)
+
+include(FindPackageHandleStandardArgs)
+include(CMakeParseArguments)
+
+# Extract the version
+if (Pandoc_EXECUTABLE)
+	execute_process(
+		COMMAND ${Pandoc_EXECUTABLE} --version
+		OUTPUT_VARIABLE _pandoc_version_tmp
+	)
+
+	if (_pandoc_version_tmp MATCHES "^pandoc[^ ]* ([0-9]+\\.[0-9]+\\.[0-9]+)")
+		set(Pandoc_VERSION "${CMAKE_MATCH_1}")
+	endif ()
+endif ()
+
+find_package_handle_standard_args(
+	Pandoc
+	FOUND_VAR Pandoc_FOUND
+	VERSION_VAR Pandoc_VERSION
+	REQUIRED_VARS Pandoc_EXECUTABLE
+)
+
+if (Pandoc_FOUND)
+	function(pandoc)
+		set(options MAKE_DIRECTORY STANDALONE TOC)
+		set(oneValueArgs FILTER FROM TARGET TEMPLATE TO OUTPUT WORKING_DIRECTORY)
+		set(multiValueArgs ARGS FOOTER HEADER METADATA SOURCES VARIABLE)
+
+		#
+		# The following variables will be set in that scope:
+		#   _pandoc_arguments		- List of all arguments that will passed to pandoc invocation.
+		#   _pandoc_depends		- List of all dependencies attached to the add_custom_command.
+		#   _pandoc_mkdir		- The mkdir command if MAKE_DIRECTORY is set
+		#   _pandoc_output_base		- The base output directory
+		#
+		cmake_parse_arguments(PANDOC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+		#
+		# Output and sources are mandatory
+		#
+		if (NOT PANDOC_OUTPUT)
+			message(FATAL_ERROR "Please define OUTPUT")
+		elseif (NOT PANDOC_SOURCES)
+			message(FATAL_ERROR "Please defines SOURCES")
+		endif ()
+
+		#
+		# Handle the filter with care.
+		#
+		# 1. If it is a target, depend on it and use a generator
+		#    expression to get its full path on the disk.
+		# 2. If it is not a target, just use the user provided path.
+		#
+		if (PANDOC_FILTER)
+			# If it is a target, add a dependency so that it is built
+			if (TARGET ${PANDOC_FILTER})
+				list(APPEND _pandoc_arguments --filter "$<TARGET_FILE:${PANDOC_FILTER}>")
+				list(APPEND _pandoc_depends ${PANDOC_FILTER})
+			else ()
+				list(APPEND _pandoc_arguments --filter ${PANDOC_FILTER})
+			endif ()
+		endif ()
+
+		if (PANDOC_TOC)
+			list(APPEND _pandoc_arguments --toc)
+		endif ()
+		if (PANDOC_STANDALONE)
+			list(APPEND _pandoc_arguments -s)
+		endif ()
+		if (PANDOC_FROM)
+			list(APPEND _pandoc_arguments -f ${PANDOC_FROM})
+		endif ()
+		if (PANDOC_TO)
+			list(APPEND _pandoc_arguments -t ${PANDOC_TO})
+		endif ()
+		if (PANDOC_TEMPLATE)
+			list(APPEND _pandoc_arguments --template ${PANDOC_TEMPLATE})
+			list(APPEND _pandoc_depends ${PANDOC_TEMPLATE})
+		endif ()
+
+		# Header, footers and body
+		foreach (h ${PANDOC_HEADER})
+			list(APPEND _pandoc_arguments -H ${h})
+			list(APPEND _pandoc_depends ${h})
+		endforeach ()
+		foreach (b ${PANDOC_BODY})
+			list(APPEND _pandoc_arguments -B ${b})
+			list(APPEND _pandoc_depends ${b})
+		endforeach ()
+		foreach (f ${PANDOC_FOOTER})
+			list(APPEND _pandoc_arguments -A ${f})
+			list(APPEND _pandoc_depends ${f})
+		endforeach ()
+
+		# Variables and metadata
+		foreach (var ${PANDOC_VARIABLE})
+			list(APPEND _pandoc_arguments -V ${var})
+		endforeach ()
+		foreach (meta ${PANDOC_METADATA})
+			list(APPEND _pandoc_arguments -M ${meta})
+		endforeach ()
+
+		# Optional list of arguments
+		foreach (arg ${PANDOC_ARGS})
+			list(APPEND _pandoc_arguments ${arg})
+		endforeach ()
+
+		# Output and sources
+		list(APPEND _pandoc_arguments -o ${PANDOC_OUTPUT})
+
+		#
+		# The following variables are set within the loop:
+		#
+		#   _pandoc_input		- The absolute path to the input file.
+		#   _pandoc_output_base		- The base output directory.
+		#
+		foreach (s ${PANDOC_SOURCES})
+			get_filename_component(_pandoc_input ${s} ABSOLUTE)
+			get_filename_component(_pandoc_output_base ${PANDOC_OUTPUT} DIRECTORY)
+			list(APPEND _pandoc_depends ${_pandoc_input})
+			list(APPEND _pandoc_arguments ${_pandoc_input})
+		endforeach ()
+
+		# Create the output directory if requested
+		if (PANDOC_MAKE_DIRECTORY)
+			set(_pandoc_mkdir ${CMAKE_COMMAND} -E make_directory ${_pandoc_output_base})
+		endif ()
+
+		add_custom_command(
+			OUTPUT ${PANDOC_OUTPUT}
+			COMMAND	${_pandoc_mkdir}
+			COMMAND	${Pandoc_EXECUTABLE} ${_pandoc_arguments}
+			DEPENDS ${_pandoc_depends} ${PANDOC_DEPENDS}
+			WORKING_DIRECTORY ${PANDOC_WORKING_DIRECTORY}
+			VERBATIM
+		)
+
+		if (PANDOC_TARGET)
+			add_custom_target(
+				${PANDOC_TARGET} ${PANDOC_ALL}
+				SOURCES ${_pandoc_depends}
+				DEPENDS ${PANDOC_OUTPUT}
+				WORKING_DIRECTORY ${PANDOC_WORKING_DIRECTORY}
+			)
+		endif ()
+	endfunction()
+endif ()
+
+mark_as_advanced(Pandoc_EXECUTABLE)
--- a/extern/gtest/CMakeLists.txt	Sun Mar 08 11:07:36 2015 +0100
+++ b/extern/gtest/CMakeLists.txt	Sun Mar 08 14:26:33 2015 +0100
@@ -28,6 +28,8 @@
 		${GoogleTest_SOURCE_DIR}
 )
 
+target_compile_options(gtest PUBLIC "-Wno-missing-field-initializers")
+
 if (NOT WIN32)
 	target_link_libraries(gtest -pthread)
 endif ()
--- a/port/asprintf.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-/*
- * asprintf.c -- basic port of asprintf / vsprintf functions
- *
- * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-/*
- * The Microsoft implementation relies on the Win32 API function
- * _vscprintf which count the number of characters needed. Otherwise the C99
- * function vsnprintf returns the number of character that would be printed.
- *
- * Finally, if we don't have C99, we use an optimistic function.
- *
- * The asprintf function is common to every implementations.
- */
-
-#if defined(_MSC_VER)
-
-/*
- * Windows implementation.
- */
-int
-vasprintf(char **res, const char *fmt, va_list ap)
-{
-	int total = _vscprintf(fmt, ap);
-
-	if (total < 0) {
-		*res = NULL;
-		return -1;
-	}
-
-	if ((*res = (char *)malloc(sizeof (total) + 1)) == NULL)
-		return -1;
-
-	return vsprintf_s(*res, total + 1, fmt, ap);
-}
-
-#elif __STDC_VERSION__ >= 199901L
-
-/*
- * C99 implementation using vsnprintf's return value.
- */
-int
-vasprintf(char **res, const char *fmt, va_list ap)
-{
-	int total, nwritten;
-	va_list copy;
-
-	va_copy(copy, ap);
-	total = vsnprintf(NULL, 0, fmt, copy);
-	va_end(copy);
-
-	if (total < 0) {
-		*res = NULL;
-		return total;
-	}
-
-	if ((*res = malloc(total + 1)) == NULL)
-		return -1;
-
-	if ((nwritten = vsnprintf(*res, total + 1, fmt, ap)) < 0) {
-		free(*res);
-		*res = NULL;
-
-		return -1;
-	}
-
-	return nwritten;
-}
-
-#else
-
-/*
- * Optimistic function fallback.
- */
-int
-vasprintf(char **res, const char *format, va_list ap)
-{
-	int rvalue, ok;
-	size_t base = 80;
-
-	if ((*res = malloc(base)) == NULL)
-		return -1;
-
-	ok = 0;
-	do {
-		rvalue = vsnprintf(*res, base, format, ap);
-
-		if ((signed int)base <= rvalue || rvalue < 0) {
-			*res = realloc(*res, base * 2);
-			base *= 2;
-		} else
-			ok = 1;
-	} while (!ok && *res != NULL);
-
-	return rvalue;
-}
-
-#endif
-
-int
-asprintf(char **res, const char *fmt, ...)
-{
-	va_list ap;
-	int rvalue;
-
-	va_start(ap, fmt);
-	rvalue = vasprintf(res, fmt, ap);
-	va_end(ap);
-
-	return rvalue;
-}
--- a/port/asprintf.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * asprintf.h -- basic port of asprintf / vsprintf functions
- *
- * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __GNUC__
-#  define _asp_at_printf(i1, i2)	__attribute__ ((format (printf, i1, i2)))
-#else
-#  define _asp_at_printf(i1, i2)
-#endif
-
-int	asprintf(char **, const char *, ...) _asp_at_printf(2, 3);
-int	vasprintf(char **, const char *, va_list);
-
-#ifdef __cplusplus
-}
-#endif
--- a/port/err.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * err.c -- formtted error messages (portable version)
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-
-#include "err.h"
-
-/*
- * These functions implements at least the same functions that can be found
- * in the NetBSD err(3) man page without printing the programe name due to
- * a portability issue.
- */
-
-void
-err(int val, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	verr(val, fmt, ap);
-	va_end(ap);
-}
-
-void
-verr(int val, const char *fmt, va_list ap)
-{
-	if (fmt) {
-		vfprintf(stderr, fmt, ap);
-		fprintf(stderr, ": ");
-	}
-
-	fprintf(stderr, "%s\n", strerror(errno));
-	exit(val);
-}
-
-void
-errx(int val, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	verrx(val, fmt, ap);
-	va_end(ap);
-}
-
-void
-verrx(int val, const char *fmt, va_list ap)
-{
-	if (fmt)
-		vfprintf(stderr, fmt, ap);
-
-	fprintf(stderr, "\n");
-
-	exit(val);
-}
-
-void
-warn(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarn(fmt, ap);
-	va_end(ap);
-}
-
-void
-vwarn(const char *fmt, va_list ap)
-{
-	if (fmt) {
-		vfprintf(stderr, fmt, ap);
-		fprintf(stderr, ": ");
-	}
-
-	fprintf(stderr, "%s\n", strerror(errno));
-}
-
-void
-warnx(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarnx(fmt, ap);
-	va_end(ap);
-}
-
-void
-vwarnx(const char *fmt, va_list ap)
-{
-	if (fmt)
-		vfprintf(stderr, fmt, ap);
-
-	fprintf(stderr, "\n");
-}
--- a/port/err.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * err.h -- formtted error messages (portable version)
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _ERR_H_
-#define _ERR_H_
-
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Attribute noreturn may helps. This may produce a warning with GCC 4.5:
- *
- * int a;
- *
- * if ((a = getstate() < 0)
- *	errx(1, "State failed");
- *
- * Because compilator does not know that errx will call exit may produce
- * a warning like `a may be used uninitialized'.
- */
-
-#if defined(__GNUC__)
-#  define __at_noreturn	__attribute__ ((noreturn))
-#elif defined(_MSC_VER)
-#  define __at_noreturn	__declspec(noreturn)
-#endif
-
-/*
- * err() functions append the format message to the stderr FILE pointer. They
- * also append the system error using strerror(errno). Then the functions exit
- * with the error code given as first argument.
- */
-
-void	err(int, const char *, ...) __at_noreturn;
-void	verr(int, const char *, va_list) __at_noreturn;
-
-/*
- * errx() functions are similar to err() except that they do not append the
- * system error message.
- */
-
-void	errx(int, const char *, ...) __at_noreturn;
-void	verrx(int, const char *, va_list) __at_noreturn;
-
-/*
- * warn() functions are similar to err() but they do not call exit().
- */
-
-void	warn(const char *, ...);
-void	vwarn(const char *, va_list);
-
-/*
- * warnx() functions are similar to warn() except that they do not append the
- * system error message.
- */
-
-void	warnx(const char *, ...);
-void	vwarnx(const char *, va_list);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ERR_H_ */
--- a/port/extern/getopt.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * getopt.c -- getopt(3) from FreeBSD (portable version)
- */
-
-/*-
- * Copyright (c) 1987, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int	opterr = 1,		/* if error message should be printed */
-	optind = 1,		/* index into parent argv vector */
-	optopt,			/* character checked for validity */
-	optreset;		/* reset getopt */
-char	*optarg;		/* argument associated with option */
-
-#define	BADCH	(int)'?'
-#define	BADARG	(int)':'
-#define	EMSG	""
-
-/*
- * getopt --
- *	Parse argc/argv argument vector.
- */
-int
-getopt(nargc, nargv, ostr)
-	int nargc;
-	char * const nargv[];
-	const char *ostr;
-{
-	static char *place = EMSG;		/* option letter processing */
-	char *oli;				/* option letter list index */
-
-	if (optreset || *place == 0) {		/* update scanning pointer */
-		optreset = 0;
-		place = nargv[optind];
-		if (optind >= nargc || *place++ != '-') {
-			/* Argument is absent or is not an option */
-			place = EMSG;
-			return (-1);
-		}
-		optopt = *place++;
-		if (optopt == '-' && *place == 0) {
-			/* "--" => end of options */
-			++optind;
-			place = EMSG;
-			return (-1);
-		}
-		if (optopt == 0) {
-			/* Solitary '-', treat as a '-' option
-			   if the program (eg su) is looking for it. */
-			place = EMSG;
-			if (strchr(ostr, '-') == NULL)
-				return (-1);
-			optopt = '-';
-		}
-	} else
-		optopt = *place++;
-
-	/* See if option letter is one the caller wanted... */
-	if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
-		if (*place == 0)
-			++optind;
-		if (opterr && *ostr != ':')
-			(void)fprintf(stderr,
-			    "illegal option -- %c\n", optopt);
-		return (BADCH);
-	}
-
-	/* Does this option need an argument? */
-	if (oli[1] != ':') {
-		/* don't need argument */
-		optarg = NULL;
-		if (*place == 0)
-			++optind;
-	} else {
-		/* Option-argument is either the rest of this argument or the
-		   entire next argument. */
-		if (*place)
-			optarg = place;
-		else if (nargc > ++optind)
-			optarg = nargv[optind];
-		else {
-			/* option-argument absent */
-			place = EMSG;
-			if (*ostr == ':')
-				return (BADARG);
-			if (opterr)
-				(void)fprintf(stderr,
-				    "option requires an argument -- %c\n", optopt);
-			return (BADCH);
-		}
-		place = EMSG;
-		++optind;
-	}
-	return (optopt);			/* return option letter */
-}
--- a/port/extern/getopt.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * getopt.h -- getopt(3) from FreeBSD (portable version)
- */
-
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Dieter Baron and Thomas Klausner.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *        This product includes software developed by the NetBSD
- *        Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _GETOPT_H_
-#define _GETOPT_H_
-
-int getopt(int, char * const [], const char *);
-
-extern char *optarg;			/* getopt(3) external variables */
-extern int optind, opterr, optopt;
-extern int optreset;			/* getopt(3) external variable */
-
-#endif /* !_GETOPT_H_ */
--- a/port/extern/queue.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,584 +0,0 @@
-/*
- * queue.h -- queue(3) from FreeBSD (portable version)
- */
-
-/*-
- * Copyright (c) 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)queue.h	8.5 (Berkeley) 8/20/94
- * $FreeBSD: src/sys/sys/queue.h,v 1.72.2.4 2011/05/24 16:04:35 mdf Exp $
- */
-
-#ifndef _SYS_QUEUE_H_
-#define	_SYS_QUEUE_H_
-
-/*
- * This file defines four types of data structures: singly-linked lists,
- * singly-linked tail queues, lists and tail queues.
- *
- * A singly-linked list is headed by a single forward pointer. The elements
- * are singly linked for minimum space and pointer manipulation overhead at
- * the expense of O(n) removal for arbitrary elements. New elements can be
- * added to the list after an existing element or at the head of the list.
- * Elements being removed from the head of the list should use the explicit
- * macro for this purpose for optimum efficiency. A singly-linked list may
- * only be traversed in the forward direction.  Singly-linked lists are ideal
- * for applications with large datasets and few or no removals or for
- * implementing a LIFO queue.
- *
- * A singly-linked tail queue is headed by a pair of pointers, one to the
- * head of the list and the other to the tail of the list. The elements are
- * singly linked for minimum space and pointer manipulation overhead at the
- * expense of O(n) removal for arbitrary elements. New elements can be added
- * to the list after an existing element, at the head of the list, or at the
- * end of the list. Elements being removed from the head of the tail queue
- * should use the explicit macro for this purpose for optimum efficiency.
- * A singly-linked tail queue may only be traversed in the forward direction.
- * Singly-linked tail queues are ideal for applications with large datasets
- * and few or no removals or for implementing a FIFO queue.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before
- * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or
- * after an existing element, at the head of the list, or at the end of
- * the list. A tail queue may be traversed in either direction.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- *
- *
- *				SLIST	LIST	STAILQ	TAILQ
- * _HEAD			+	+	+	+
- * _HEAD_INITIALIZER		+	+	+	+
- * _ENTRY			+	+	+	+
- * _INIT			+	+	+	+
- * _EMPTY			+	+	+	+
- * _FIRST			+	+	+	+
- * _NEXT			+	+	+	+
- * _PREV			-	-	-	+
- * _LAST			-	-	+	+
- * _FOREACH			+	+	+	+
- * _FOREACH_SAFE		+	+	+	+
- * _FOREACH_REVERSE		-	-	-	+
- * _FOREACH_REVERSE_SAFE	-	-	-	+
- * _INSERT_HEAD			+	+	+	+
- * _INSERT_BEFORE		-	+	-	+
- * _INSERT_AFTER		+	+	+	+
- * _INSERT_TAIL			-	-	+	+
- * _CONCAT			-	-	+	+
- * _REMOVE_AFTER		+	-	+	-
- * _REMOVE_HEAD			+	-	+	-
- * _REMOVE			+	+	+	+
- * _SWAP			+	+	+	+
- *
- */
-
-/*
- * winnt.h includes some variables like SLIST_ENTRY, so undef all. If this
- * file is used it is probably because the user want is instead of
- * windows ones.
- */
-
-#undef SLIST_EMPTY
-#undef SLIST_ENTRY
-#undef SLIST_FIRST
-#undef SLIST_FOREACH
-#undef SLIST_FOREACH_SAFE
-#undef SLIST_HEAD
-#undef SLIST_HEAD_INITIALIZER
-#undef SLIST_INIT
-#undef SLIST_INSERT_AFTER
-#undef SLIST_INSERT_HEAD
-#undef SLIST_NEXT
-#undef SLIST_REMOVE_AFTER
-#undef SLIST_REMOVE_HEAD
-#undef SLIST_REMOVE
-#undef SLIST_SWAP
-#undef STAILQ_CONCAT
-#undef STAILQ_EMPTY
-#undef STAILQ_ENTRY
-#undef STAILQ_FIRST
-#undef STAILQ_FOREACH
-#undef STAILQ_FOREACH_SAFE
-#undef STAILQ_HEAD
-#undef STAILQ_HEAD_INITIALIZER
-#undef STAILQ_INIT
-#undef STAILQ_INSERT_AFTER
-#undef STAILQ_INSERT_HEAD
-#undef STAILQ_INSERT_TAIL
-#undef STAILQ_LAST
-#undef STAILQ_NEXT
-#undef STAILQ_REMOVE_AFTER
-#undef STAILQ_REMOVE_HEAD
-#undef STAILQ_REMOVE
-#undef STAILQ_SWAP
-#undef LIST_EMPTY
-#undef LIST_ENTRY
-#undef LIST_FIRST
-#undef LIST_FOREACH
-#undef LIST_FOREACH_SAFE
-#undef LIST_HEAD
-#undef LIST_HEAD_INITIALIZER
-#undef LIST_INIT
-#undef LIST_INSERT_AFTER
-#undef LIST_INSERT_BEFORE
-#undef LIST_INSERT_HEAD
-#undef LIST_NEXT
-#undef LIST_REMOVE
-#undef LIST_SWAP
-#undef TAILQ_CONCAT
-#undef TAILQ_EMPTY
-#undef TAILQ_ENTRY
-#undef TAILQ_FIRST
-#undef TAILQ_FOREACH
-#undef TAILQ_FOREACH_SAFE
-#undef TAILQ_FOREACH_REVERSE
-#undef TAILQ_FOREACH_REVERSE_SAFE
-#undef TAILQ_HEAD
-#undef TAILQ_HEAD_INITIALIZER
-#undef TAILQ_INIT
-#undef TAILQ_INSERT_AFTER
-#undef TAILQ_INSERT_BEFORE
-#undef TAILQ_INSERT_HEAD
-#undef TAILQ_INSERT_TAIL
-#undef TAILQ_LAST
-#undef TAILQ_NEXT
-#undef TAILQ_PREV
-#undef TAILQ_REMOVE
-#undef TAILQ_SWAP
-
-/*
- * Singly-linked List declarations.
- */
-#define	SLIST_HEAD(name, type)						\
-struct name {								\
-	struct type *slh_first;	/* first element */			\
-}
-
-#define	SLIST_HEAD_INITIALIZER(head)					\
-	{ NULL }
-
-#define	SLIST_ENTRY(type)						\
-struct {								\
-	struct type *sle_next;	/* next element */			\
-}
-
-/*
- * Singly-linked List functions.
- */
-#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
-
-#define	SLIST_FIRST(head)	((head)->slh_first)
-
-#define	SLIST_FOREACH(var, head, field)					\
-	for ((var) = SLIST_FIRST((head));				\
-	    (var);							\
-	    (var) = SLIST_NEXT((var), field))
-
-#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = SLIST_FIRST((head));				\
-	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
-	    (var) = (tvar))
-
-#define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
-	for ((varp) = &SLIST_FIRST((head));				\
-	    ((var) = *(varp)) != NULL;					\
-	    (varp) = &SLIST_NEXT((var), field))
-
-#define	SLIST_INIT(head) do {						\
-	SLIST_FIRST((head)) = NULL;					\
-} while (0)
-
-#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
-	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
-	SLIST_NEXT((slistelm), field) = (elm);				\
-} while (0)
-
-#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
-	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
-	SLIST_FIRST((head)) = (elm);					\
-} while (0)
-
-#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
-
-#define	SLIST_REMOVE(head, elm, type, field) do {			\
-	if (SLIST_FIRST((head)) == (elm)) {				\
-		SLIST_REMOVE_HEAD((head), field);			\
-	}								\
-	else {								\
-		struct type *curelm = SLIST_FIRST((head));		\
-		while (SLIST_NEXT(curelm, field) != (elm))		\
-			curelm = SLIST_NEXT(curelm, field);		\
-		SLIST_REMOVE_AFTER(curelm, field);			\
-	}								\
-} while (0)
-
-#define SLIST_REMOVE_AFTER(elm, field) do {				\
-	SLIST_NEXT(elm, field) =					\
-	    SLIST_NEXT(SLIST_NEXT(elm, field), field);			\
-} while (0)
-
-#define	SLIST_REMOVE_HEAD(head, field) do {				\
-	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
-} while (0)
-
-#define SLIST_SWAP(head1, head2, type) do {				\
-	struct type *swap_first = SLIST_FIRST(head1);			\
-	SLIST_FIRST(head1) = SLIST_FIRST(head2);			\
-	SLIST_FIRST(head2) = swap_first;				\
-} while (0)
-
-/*
- * Singly-linked Tail queue declarations.
- */
-#define	STAILQ_HEAD(name, type)						\
-struct name {								\
-	struct type *stqh_first;/* first element */			\
-	struct type **stqh_last;/* addr of last next element */		\
-}
-
-#define	STAILQ_HEAD_INITIALIZER(head)					\
-	{ NULL, &(head).stqh_first }
-
-#define	STAILQ_ENTRY(type)						\
-struct {								\
-	struct type *stqe_next;	/* next element */			\
-}
-
-/*
- * Singly-linked Tail queue functions.
- */
-#define	STAILQ_CONCAT(head1, head2) do {				\
-	if (!STAILQ_EMPTY((head2))) {					\
-		*(head1)->stqh_last = (head2)->stqh_first;		\
-		(head1)->stqh_last = (head2)->stqh_last;		\
-		STAILQ_INIT((head2));					\
-	}								\
-} while (0)
-
-#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
-
-#define	STAILQ_FIRST(head)	((head)->stqh_first)
-
-#define	STAILQ_FOREACH(var, head, field)				\
-	for((var) = STAILQ_FIRST((head));				\
-	   (var);							\
-	   (var) = STAILQ_NEXT((var), field))
-
-
-#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = STAILQ_FIRST((head));				\
-	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
-	    (var) = (tvar))
-
-#define	STAILQ_INIT(head) do {						\
-	STAILQ_FIRST((head)) = NULL;					\
-	(head)->stqh_last = &STAILQ_FIRST((head));			\
-} while (0)
-
-#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
-	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
-		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
-	STAILQ_NEXT((tqelm), field) = (elm);				\
-} while (0)
-
-#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
-	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
-		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
-	STAILQ_FIRST((head)) = (elm);					\
-} while (0)
-
-#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
-	STAILQ_NEXT((elm), field) = NULL;				\
-	*(head)->stqh_last = (elm);					\
-	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
-} while (0)
-
-#define	STAILQ_LAST(head, type, field)					\
-	(STAILQ_EMPTY((head)) ?						\
-		NULL :							\
-	        ((struct type *)(void *)				\
-		((char *)((head)->stqh_last) - __offsetof(struct type, field))))
-
-#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
-
-#define	STAILQ_REMOVE(head, elm, type, field) do {			\
-	if (STAILQ_FIRST((head)) == (elm)) {				\
-		STAILQ_REMOVE_HEAD((head), field);			\
-	}								\
-	else {								\
-		struct type *curelm = STAILQ_FIRST((head));		\
-		while (STAILQ_NEXT(curelm, field) != (elm))		\
-			curelm = STAILQ_NEXT(curelm, field);		\
-		STAILQ_REMOVE_AFTER(head, curelm, field);		\
-	}								\
-} while (0)
-
-#define STAILQ_REMOVE_AFTER(head, elm, field) do {			\
-	if ((STAILQ_NEXT(elm, field) =					\
-	     STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
-		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
-} while (0)
-
-#define	STAILQ_REMOVE_HEAD(head, field) do {				\
-	if ((STAILQ_FIRST((head)) =					\
-	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
-		(head)->stqh_last = &STAILQ_FIRST((head));		\
-} while (0)
-
-#define STAILQ_SWAP(head1, head2, type) do {				\
-	struct type *swap_first = STAILQ_FIRST(head1);			\
-	struct type **swap_last = (head1)->stqh_last;			\
-	STAILQ_FIRST(head1) = STAILQ_FIRST(head2);			\
-	(head1)->stqh_last = (head2)->stqh_last;			\
-	STAILQ_FIRST(head2) = swap_first;				\
-	(head2)->stqh_last = swap_last;					\
-	if (STAILQ_EMPTY(head1))					\
-		(head1)->stqh_last = &STAILQ_FIRST(head1);		\
-	if (STAILQ_EMPTY(head2))					\
-		(head2)->stqh_last = &STAILQ_FIRST(head2);		\
-} while (0)
-
-/*
- * List declarations.
- */
-#define	LIST_HEAD(name, type)						\
-struct name {								\
-	struct type *lh_first;	/* first element */			\
-}
-
-#define	LIST_HEAD_INITIALIZER(head)					\
-	{ NULL }
-
-#define	LIST_ENTRY(type)						\
-struct {								\
-	struct type *le_next;	/* next element */			\
-	struct type **le_prev;	/* address of previous next element */	\
-}
-
-/*
- * List functions.
- */
-
-#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
-
-#define	LIST_FIRST(head)	((head)->lh_first)
-
-#define	LIST_FOREACH(var, head, field)					\
-	for ((var) = LIST_FIRST((head));				\
-	    (var);							\
-	    (var) = LIST_NEXT((var), field))
-
-#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = LIST_FIRST((head));				\
-	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
-	    (var) = (tvar))
-
-#define	LIST_INIT(head) do {						\
-	LIST_FIRST((head)) = NULL;					\
-} while (0)
-
-#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
-	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
-		LIST_NEXT((listelm), field)->field.le_prev =		\
-		    &LIST_NEXT((elm), field);				\
-	LIST_NEXT((listelm), field) = (elm);				\
-	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
-} while (0)
-
-#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
-	(elm)->field.le_prev = (listelm)->field.le_prev;		\
-	LIST_NEXT((elm), field) = (listelm);				\
-	*(listelm)->field.le_prev = (elm);				\
-	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
-} while (0)
-
-#define	LIST_INSERT_HEAD(head, elm, field) do {				\
-	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
-		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
-	LIST_FIRST((head)) = (elm);					\
-	(elm)->field.le_prev = &LIST_FIRST((head));			\
-} while (0)
-
-#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
-
-#define	LIST_REMOVE(elm, field) do {					\
-	if (LIST_NEXT((elm), field) != NULL)				\
-		LIST_NEXT((elm), field)->field.le_prev = 		\
-		    (elm)->field.le_prev;				\
-	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
-} while (0)
-
-#define LIST_SWAP(head1, head2, type, field) do {			\
-	struct type *swap_tmp = LIST_FIRST((head1));			\
-	LIST_FIRST((head1)) = LIST_FIRST((head2));			\
-	LIST_FIRST((head2)) = swap_tmp;					\
-	if ((swap_tmp = LIST_FIRST((head1))) != NULL)			\
-		swap_tmp->field.le_prev = &LIST_FIRST((head1));		\
-	if ((swap_tmp = LIST_FIRST((head2))) != NULL)			\
-		swap_tmp->field.le_prev = &LIST_FIRST((head2));		\
-} while (0)
-
-/*
- * Tail queue declarations.
- */
-#define	TAILQ_HEAD(name, type)						\
-struct name {								\
-	struct type *tqh_first;	/* first element */			\
-	struct type **tqh_last;	/* addr of last next element */		\
-}
-
-#define	TAILQ_HEAD_INITIALIZER(head)					\
-	{ NULL, &(head).tqh_first }
-
-#define	TAILQ_ENTRY(type)						\
-struct {								\
-	struct type *tqe_next;	/* next element */			\
-	struct type **tqe_prev;	/* address of previous next element */	\
-}
-
-/*
- * Tail queue functions.
- */
-
-#define	TAILQ_CONCAT(head1, head2, field) do {				\
-	if (!TAILQ_EMPTY(head2)) {					\
-		*(head1)->tqh_last = (head2)->tqh_first;		\
-		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
-		(head1)->tqh_last = (head2)->tqh_last;			\
-		TAILQ_INIT((head2));					\
-	}								\
-} while (0)
-
-#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
-
-#define	TAILQ_FIRST(head)	((head)->tqh_first)
-
-#define	TAILQ_FOREACH(var, head, field)					\
-	for ((var) = TAILQ_FIRST((head));				\
-	    (var);							\
-	    (var) = TAILQ_NEXT((var), field))
-
-#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = TAILQ_FIRST((head));				\
-	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
-	    (var) = (tvar))
-
-#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
-	for ((var) = TAILQ_LAST((head), headname);			\
-	    (var);							\
-	    (var) = TAILQ_PREV((var), headname, field))
-
-#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
-	for ((var) = TAILQ_LAST((head), headname);			\
-	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
-	    (var) = (tvar))
-
-#define	TAILQ_INIT(head) do {						\
-	TAILQ_FIRST((head)) = NULL;					\
-	(head)->tqh_last = &TAILQ_FIRST((head));			\
-} while (0)
-
-#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
-		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
-		    &TAILQ_NEXT((elm), field);				\
-	else {								\
-		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
-	}								\
-	TAILQ_NEXT((listelm), field) = (elm);				\
-	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
-} while (0)
-
-#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
-	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
-	TAILQ_NEXT((elm), field) = (listelm);				\
-	*(listelm)->field.tqe_prev = (elm);				\
-	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
-} while (0)
-
-#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
-	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
-		TAILQ_FIRST((head))->field.tqe_prev =			\
-		    &TAILQ_NEXT((elm), field);				\
-	else								\
-		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
-	TAILQ_FIRST((head)) = (elm);					\
-	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
-} while (0)
-
-#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
-	TAILQ_NEXT((elm), field) = NULL;				\
-	(elm)->field.tqe_prev = (head)->tqh_last;			\
-	*(head)->tqh_last = (elm);					\
-	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
-} while (0)
-
-#define	TAILQ_LAST(head, headname)					\
-	(*(((struct headname *)((head)->tqh_last))->tqh_last))
-
-#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-
-#define	TAILQ_PREV(elm, headname, field)				\
-	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-
-#define	TAILQ_REMOVE(head, elm, field) do {				\
-	if ((TAILQ_NEXT((elm), field)) != NULL)				\
-		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
-		    (elm)->field.tqe_prev;				\
-	else {								\
-		(head)->tqh_last = (elm)->field.tqe_prev;		\
-	}								\
-	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
-} while (0)
-
-#define TAILQ_SWAP(head1, head2, type, field) do {			\
-	struct type *swap_first = (head1)->tqh_first;			\
-	struct type **swap_last = (head1)->tqh_last;			\
-	(head1)->tqh_first = (head2)->tqh_first;			\
-	(head1)->tqh_last = (head2)->tqh_last;				\
-	(head2)->tqh_first = swap_first;				\
-	(head2)->tqh_last = swap_last;					\
-	if ((swap_first = (head1)->tqh_first) != NULL)			\
-		swap_first->field.tqe_prev = &(head1)->tqh_first;	\
-	else								\
-		(head1)->tqh_last = &(head1)->tqh_first;		\
-	if ((swap_first = (head2)->tqh_first) != NULL)			\
-		swap_first->field.tqe_prev = &(head2)->tqh_first;	\
-	else								\
-		(head2)->tqh_last = &(head2)->tqh_first;		\
-} while (0)
-
-#endif /* !_SYS_QUEUE_H_ */
--- a/port/extern/stdbool.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2000 Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/include/stdbool.h,v 1.7.28.1.2.1 2011/11/11 04:20:22 kensmith Exp $
- */
-
-#ifndef _STDBOOL_H_
-#define	_STDBOOL_H_	
-
-#define	__bool_true_false_are_defined	1
-
-#ifndef __cplusplus
-
-#define	false	0
-#define	true	1
-
-/* Very portable bool version */
-typedef	char	bool;
-
-#endif /* !__cplusplus */
-
-#endif /* !_STDBOOL_H_ */
--- a/port/extern/strlcat.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 2012 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stddef.h>
-
-/*
- * Appends src to string dst of size siz (unlike strncat, siz is the
- * full size of dst, not space left).  At most siz-1 characters
- * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
- * Returns strlen(src) + MIN(siz, strlen(initial dst)).
- * If retval >= siz, truncation occurred.
- */
-size_t
-strlcat(char *dst, const char *src, size_t siz)
-{
-	char *d = dst;
-	const char *s = src;
-	size_t n = siz;
-	size_t dlen;
-
-	/* Find the end of dst and adjust bytes left but don't go past end */
-	while (n-- != 0 && *d != '\0')
-		d++;
-	dlen = d - dst;
-	n = siz - dlen;
-
-	if (n == 0)
-		return(dlen + strlen(s));
-	while (*s != '\0') {
-		if (n != 1) {
-			*d++ = *s;
-			n--;
-		}
-		s++;
-	}
-	*d = '\0';
-
-	return(dlen + (s - src));	/* count does not include NUL */
-}
--- a/port/extern/strlcpy.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 2012 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stddef.h>
-
-/*
- * Copy src to string dst of size siz.  At most siz-1 characters
- * will be copied.  Always NUL terminates (unless siz == 0).
- * Returns strlen(src); if retval >= siz, truncation occurred.
- */
-size_t
-strlcpy(char *dst, const char *src, size_t siz)
-{
-	char *d = dst;
-	const char *s = src;
-	size_t n = siz;
-
-	/* Copy as many bytes as will fit */
-	if (n != 0) {
-		while (--n != 0) {
-			if ((*d++ = *s++) == '\0')
-				break;
-		}
-	}
-
-	/* Not enough room in dst, add NUL and traverse rest of src */
-	if (n == 0) {
-		if (siz != 0)
-			*d = '\0';		/* NUL-terminate dst */
-		while (*s++)
-			;
-	}
-
-	return(s - src - 1);	/* count does not include NUL */
-}
--- a/port/setprogname.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * setprogname.c -- get or set the program name
- *
- * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Do not return NULL if the developer didn't call setprogname to
- * prevent useless segfault.
- */
-static const char	*g_pname = "";
-
-void
-setprogname(const char *progname)
-{
-	const char *p;
-
-	/* Seek last / or \ on windows */
-	if ((p = strrchr(progname, '/')) || (p = strrchr(progname, '\\')))
-		g_pname = &p[1];
-	else
-		g_pname = progname;
-}
-
-const char *
-getprogname(void)
-{
-	return g_pname;
-}
--- a/port/setprogname.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * setprogname.h -- get or set the program name
- *
- * Copyright (c) 2011, 2012 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void		setprogname(const char *);
-const char	*getprogname(void);
-
-#ifdef __cplusplus
-}
-#endif
--- a/port/strdup.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * strdup.c -- duplicate a string
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-char *
-strdup(const char *src)
-{
-	char *dst;
-	size_t len;
-
-	len = strlen(src);
-
-	if ((dst = calloc(len + 1, sizeof (char))) == NULL)
-		return NULL;
-
-	return strcpy(dst, src);
-}
--- a/port/strdup.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * strdup.h -- duplicate a string
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-char	*strdup(const char *);
-
-#ifdef __cplusplus
-}
-#endif
-
--- a/port/strndup.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * strndup.c -- duplicate a string
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-char *
-strndup(const char *src, size_t len)
-{
-	size_t tocopy;
-	char *dst;
-
-	for (tocopy = 0; tocopy < len && src[tocopy] != '\0'; ++tocopy)
-		continue;
-
-	if ((dst = calloc(tocopy + 1, 1)) != NULL)
-		strncpy(dst, src, tocopy);
-
-	return dst;
-}
--- a/port/strndup.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * strndup.h -- duplicate a string
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-char	*strndup(const char *, size_t);
-
-#ifdef __cplusplus
-}
-#endif
--- a/port/strsep.c	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * strsep.c -- separate a string by delimiters
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-char *
-strsep(char **stringp, const char *delim)
-{
-	char *item, *ptr;
-
-	if (*stringp == NULL || delim[0] == '\0')
-		return NULL;
-
-	item = *stringp;	
-	if ((ptr = strpbrk(*stringp, delim)) == NULL) {
-		*stringp = NULL;
-		return item;
-	}
-
-	*ptr = '\0';
-	*stringp = ptr + 1;
-
-	return item;
-}
--- a/port/strsep.h	Sun Mar 08 11:07:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * strsep.h -- separate a string by delimiters
- *
- * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-char	*strsep(char **, const char *);
-
-#ifdef __cplusplus
-}
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/CMakeLists.txt	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,21 @@
+#
+# CMakeLists.txt -- code building for common code
+#
+# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(tools)
+
+add_executable(mdtohtml mdtohtml.cpp)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/mdtohtml.cpp	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,38 @@
+/*
+ * mdtohtml.cpp -- convert .md links to .html for local documentation
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+using namespace std;
+
+int main(void)
+{
+	string content;
+	string::size_type pos;
+
+	copy(istreambuf_iterator<char>(cin), istreambuf_iterator<char>(), back_inserter(content));
+
+	while ((pos = content.find(".md")) != string::npos)
+		content.replace(pos, 3, ".html");
+
+	copy(content.begin(), content.end(), ostreambuf_iterator<char>(cout));
+
+	return 0;
+}