changeset 189:bb70bb9e41eb

Irccd: use native Duktape API
author David Demelier <markand@malikania.fr>
date Fri, 03 Jun 2016 13:28:10 +0200
parents 0de84b31842b
children cb61cc16e2b6
files cmake/internal/sysconfig.hpp.in lib/irccd/duktape.hpp lib/irccd/js.hpp lib/irccd/mod-directory.cpp lib/irccd/mod-elapsed-timer.cpp lib/irccd/mod-file.cpp lib/irccd/mod-file.hpp lib/irccd/mod-irccd.cpp lib/irccd/mod-irccd.hpp lib/irccd/mod-logger.cpp lib/irccd/mod-plugin.cpp lib/irccd/mod-plugin.hpp lib/irccd/mod-server.cpp lib/irccd/mod-server.hpp lib/irccd/mod-system.cpp lib/irccd/mod-timer.cpp lib/irccd/mod-unicode.cpp lib/irccd/mod-util.cpp lib/irccd/net.hpp lib/irccd/plugin-js.cpp lib/irccd/plugin-js.hpp lib/irccd/server-event.cpp
diffstat 22 files changed, 1497 insertions(+), 3895 deletions(-) [+]
line wrap: on
line diff
--- a/cmake/internal/sysconfig.hpp.in	Tue May 31 22:33:32 2016 +0200
+++ b/cmake/internal/sysconfig.hpp.in	Fri Jun 03 13:28:10 2016 +0200
@@ -104,7 +104,7 @@
 #  if defined(IRCCD_BUILDING_DLL)
 #    define IRCCD_EXPORT __declspec(dllexport)
 #  else
-#    define IRCCD_EXPORT __declspec(dllimport)
+#    define IRCCD_EXPORT
 #  endif
 #else
 #  define IRCCD_EXPORT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/irccd/duktape.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -0,0 +1,440 @@
+/*
+ * duktape.hpp -- Duktape extras
+ *
+ * Copyright (c) 2016 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 IRCCD_DUKTAPE_HPP
+#define IRCCD_DUKTAPE_HPP
+
+/**
+ * \file duktape.hpp
+ * \brief Bring some extras to Duktape C library.
+ * \author David Demelier <markand@malikania.fr>
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include <duktape.h>
+
+namespace irccd {
+
+/**
+ * \class StackAssert
+ * \brief Stack sanity checker.
+ *
+ * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor
+ * will examinate if the stack size matches the user expected size.
+ *
+ * When compiled with NDEBUG, this class does nothing.
+ *
+ * To use it, just declare an lvalue at the beginning of your function.
+ */
+class StackAssert {
+#if !defined(NDEBUG)
+private:
+	duk_context *m_context;
+	unsigned m_expected;
+	unsigned m_begin;
+#endif
+
+public:
+	/**
+	 * Create the stack checker.
+	 *
+	 * No-op if NDEBUG is set.
+	 *
+	 * \param ctx the context
+	 * \param expected the size expected relative to the already existing values
+	 */
+	inline StackAssert(duk_context *ctx, unsigned expected = 0) noexcept
+#if !defined(NDEBUG)
+		: m_context(ctx)
+		, m_expected(expected)
+		, m_begin(static_cast<unsigned>(duk_get_top(ctx)))
+#endif
+	{
+#if defined(NDEBUG)
+		(void)ctx;
+		(void)expected;
+#endif
+	}
+
+	/**
+	 * Verify the expected size.
+	 *
+	 * No-op if NDEBUG is set.
+	 */
+	inline ~StackAssert() noexcept
+	{
+#if !defined(NDEBUG)
+		if (static_cast<unsigned>(duk_get_top(m_context)) - m_begin != m_expected) {
+			std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n");
+			std::fprintf(stderr, "  Size at start:            %u\n", m_begin);
+			std::fprintf(stderr, "  Size at end:              %d\n", duk_get_top(m_context));
+			std::fprintf(stderr, "  Expected (user):          %u\n", m_expected);
+			std::fprintf(stderr, "  Expected (adjusted):      %u\n", m_expected + m_begin);
+			std::fprintf(stderr, "  Number of stale values:   %u\n", duk_get_top(m_context) - m_begin - m_expected);
+			std::abort();
+		}
+#endif
+	}
+};
+
+/**
+ * \class Exception
+ * \brief Error description.
+ *
+ * This class fills the fields got in an Error object.
+ */
+class Exception : public std::exception {
+public:
+	std::string name;		//!< name of error
+	std::string message;		//!< error message
+	std::string stack;		//!< stack if available
+	std::string fileName;		//!< filename if applicable
+	int lineNumber{0};		//!< line number if applicable
+
+	/**
+	 * Get the error message. This effectively returns message field.
+	 *
+	 * \return the message
+	 */
+	const char *what() const noexcept override
+	{
+		return message.c_str();
+	}
+};
+
+/**
+ * \brief RAII based Duktape handler.
+ *
+ * This class is implicitly convertible to duk_context for convenience.
+ */
+class UniqueContext {
+private:
+	using Deleter = void (*)(duk_context *);
+	using Handle = std::unique_ptr<duk_context, Deleter>;
+
+	Handle m_handle;
+
+	UniqueContext(const UniqueContext &) = delete;
+	UniqueContext &operator=(const UniqueContext &) = delete;
+
+public:
+	/**
+	 * Create default context.
+	 */
+	inline UniqueContext()
+		: m_handle(duk_create_heap_default(), duk_destroy_heap)
+	{
+	}
+
+	/**
+	 * Default move constructor.
+	 */
+	UniqueContext(UniqueContext &&) noexcept = default;
+
+	/**
+	 * Convert the context to the native Duktape/C type.
+	 *
+	 * \return the duk_context
+	 */
+	inline operator duk_context *() noexcept
+	{
+		return m_handle.get();
+	}
+
+	/**
+	 * Convert the context to the native Duktape/C type.
+	 *
+	 * \return the duk_context
+	 */
+	inline operator duk_context *() const noexcept
+	{
+		return m_handle.get();
+	}
+
+	/**
+	 * Default move assignment operator.
+	 *
+	 * \return this
+	 */
+	UniqueContext &operator=(UniqueContext &&) noexcept = delete;
+};
+
+/**
+ * \class Error
+ * \brief Base ECMAScript error class.
+ * \warning Override the function create for your own exceptions
+ */
+class Error {
+private:
+	int m_type{DUK_ERR_ERROR};
+	std::string m_message;
+
+protected:
+	/**
+	 * Constructor with a type of error specified, specially designed for derived errors.
+	 *
+	 * \param type of error (e.g. DUK_ERR_ERROR)
+	 * \param message the message
+	 */
+	inline Error(int type, std::string message) noexcept
+		: m_type(type)
+		, m_message(std::move(message))
+	{
+	}
+
+public:
+	/**
+	 * Constructor with a message.
+	 *
+	 * \param message the message
+	 */
+	inline Error(std::string message) noexcept
+		: m_message(std::move(message))
+	{
+	}
+
+	/**
+	 * Create the exception on the stack.
+	 *
+	 * \note the default implementation search for the global variables
+	 * \param ctx the context
+	 */
+	virtual void raise(duk_context *ctx) const
+	{
+		duk_error(ctx, m_type, "%s", m_message.c_str());
+	}
+};
+
+/**
+ * \class EvalError
+ * \brief Error in eval() function.
+ */
+class EvalError : public Error {
+public:
+	/**
+	 * Construct an EvalError.
+	 *
+	 * \param message the message
+	 */
+	inline EvalError(std::string message) noexcept
+		: Error(DUK_ERR_EVAL_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class RangeError
+ * \brief Value is out of range.
+ */
+class RangeError : public Error {
+public:
+	/**
+	 * Construct an RangeError.
+	 *
+	 * \param message the message
+	 */
+	inline RangeError(std::string message) noexcept
+		: Error(DUK_ERR_RANGE_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class ReferenceError
+ * \brief Trying to use a variable that does not exist.
+ */
+class ReferenceError : public Error {
+public:
+	/**
+	 * Construct an ReferenceError.
+	 *
+	 * \param message the message
+	 */
+	inline ReferenceError(std::string message) noexcept
+		: Error(DUK_ERR_REFERENCE_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class SyntaxError
+ * \brief Syntax error in the script.
+ */
+class SyntaxError : public Error {
+public:
+	/**
+	 * Construct an SyntaxError.
+	 *
+	 * \param message the message
+	 */
+	inline SyntaxError(std::string message) noexcept
+		: Error(DUK_ERR_SYNTAX_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class TypeError
+ * \brief Invalid type given.
+ */
+class TypeError : public Error {
+public:
+	/**
+	 * Construct an TypeError.
+	 *
+	 * \param message the message
+	 */
+	inline TypeError(std::string message) noexcept
+		: Error(DUK_ERR_TYPE_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class URIError
+ * \brief URI manipulation failure.
+ */
+class URIError : public Error {
+public:
+	/**
+	 * Construct an URIError.
+	 *
+	 * \param message the message
+	 */
+	inline URIError(std::string message) noexcept
+		: Error(DUK_ERR_URI_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * Get the error object when a JavaScript error has been thrown (e.g. eval failure).
+ *
+ * \param ctx the context
+ * \param index the index
+ * \param pop if true, also remove the exception from the stack
+ * \return the information
+ */
+inline Exception duk_exception(duk_context *ctx, int index, bool pop = true)
+{
+	Exception ex;
+
+	index = duk_normalize_index(ctx, index);
+
+	duk_get_prop_string(ctx, index, "name");
+	ex.name = duk_to_string(ctx, -1);
+	duk_get_prop_string(ctx, index, "message");
+	ex.message = duk_to_string(ctx, -1);
+	duk_get_prop_string(ctx, index, "fileName");
+	ex.fileName = duk_to_string(ctx, -1);
+	duk_get_prop_string(ctx, index, "lineNumber");
+	ex.lineNumber = duk_to_int(ctx, -1);
+	duk_get_prop_string(ctx, index, "stack");
+	ex.stack = duk_to_string(ctx, -1);
+	duk_pop_n(ctx, 5);
+
+	if (pop)
+		duk_remove(ctx, index);
+
+	return ex;
+}
+
+/**
+ * Enumerate an object or an array at the specified index.
+ *
+ * \param ctx the context
+ * \param index the object or array index
+ * \param flags the optional flags to pass to duk_enum
+ * \param getvalue set to true if you want to extract the value
+ * \param func the function to call for each properties
+ */
+template <typename Func>
+void duk_enumerate(duk_context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
+{
+	duk_enum(ctx, index, flags);
+
+	while (duk_next(ctx, -1, getvalue)) {
+		func(ctx);
+		duk_pop_n(ctx, 1 + (getvalue ? 1 : 0));
+	}
+
+	duk_pop(ctx);
+}
+
+/**
+ * Throw an ECMAScript exception.
+ *
+ * \param ctx the context
+ * \param ex the exception
+ */
+template <typename Exception>
+void duk_throw(duk_context *ctx, const Exception &ex)
+{
+	ex.raise(ctx);
+}
+
+/**
+ * Get a string, return 0 if not a string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the string
+ */
+inline std::string duk_get_stdstring(duk_context *ctx, int index)
+{
+	duk_size_t size;
+	const char *text = duk_get_lstring(ctx, index, &size);
+
+	return std::string(text, size);
+}
+
+/**
+ * Require a string, throws a JavaScript exception if not a string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the string
+ */
+inline std::string duk_require_stdstring(duk_context *ctx, int index)
+{
+	duk_size_t size;
+	const char *text = duk_require_lstring(ctx, index, &size);
+
+	return std::string(text, size);
+}
+
+/**
+ * Push a C++ string.
+ *
+ * \param ctx the context
+ * \param str the string
+ */
+inline void duk_push_stdstring(duk_context *ctx, const std::string &str)
+{
+	duk_push_lstring(ctx, str.data(), str.length());
+}
+
+} // !irccd
+
+#endif // !IRCCD_DUKTAPE_HPP
--- a/lib/irccd/js.hpp	Tue May 31 22:33:32 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2867 +0,0 @@
-/*
- * js.hpp -- JavaScript C++14 wrapper for Duktape
- *
- * Copyright (c) 2016 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 IRCCD_JS_HPP
-#define IRCCD_JS_HPP
-
-/**
- * \file js.hpp
- * \brief Bring JavaScript using Duktape.
- * \author David Demelier <markand@malikania.fr>
- *
- * This file provides usual Duktape function renamed and placed into `duk` namespace. It also replaces error
- * code with exceptions when possible.
- *
- * For convenience, this file also provides templated functions, overloads and much more.
- */
-
-/**
- * \page js JavaScript binding
- * \brief JavaScript binding using Duktape
- *
- * This page will show you how to setup this module to host JavaScript environment into your C++ application.
- *
- * ## Duktape
- *
- * Duktape is a C library designed for performance, small footprint and conformance. This wrapper is built top of it and
- * requires it at build and runtime.
- *
- * It is highly recommended that you read the [Duktape guide](http://duktape.org/guide.html) before continuing because
- * a lot of concepts are kept as-is.
- *
- * ## Installation
- *
- * You need the Duktape source amalgamation, it is provided with this module.
- *
- * When compiling, be sure to enable `-DDUK_OPT_CPP_EXCEPTIONS` and that Duktape source file has **cpp** extension.
- *
- * Just copy the **js.hpp** file and include it into your project. The header depends on **duktape.h** so be sure to
- * provide it when compiling.
- *
- *   - \subpage js-init
- *   - \subpage js-types
- *   - \subpage js-basics
- *   - \subpage js-more
- */
-
-/**
- * \page js-init Initialization
- * \brief Context initialization.
- *
- * To host JavaScript, you need a context. Usually one is sufficient but you can create as many as you want but they
- * won't share any resource.
- *
- * \code
- * #include "js.hpp"
- *
- * int main()
- * {
- *   duk::UniqueContext ctx;
- *
- *   return 0;
- * }
- * \endcode
- *
- * The duk::UniqueContext class is a RAII based wrapper around the native duk_context structure. It is automatically created and closed
- * in the destructor.
- *
- * Be sure to not keep any pointer to it.
- */
-
-/**
- * \page js-types Predefined types
- * \brief Default duk::TypeTraits specializations
- *
- * The following specializations are provided with libjs.
- *
- * ## Primitive types
- *
- * | Type           | Support                          | Remarks                               |
- * |----------------|----------------------------------|---------------------------------------|
- * | `int`          | get, is, optional, push, require |                                       |
- * | `bool`         | get, is, optional, push, require |                                       |
- * | `double`       | get, is, optional, push, require |                                       |
- * | `std::string`  | get, is, optional, push, require | can contain '\0' and binary data      |
- * | `const char *` | get, is, optional, push, require |                                       |
- * | `unsigned`     | get, is, optional, push, require |                                       |
- * | T *            | get, is, optional, push, require | raw pointer, never deleted by Duktape |
- *
- * ## Special JavaScript types
- *
- * The following types are used to create or inspect JavaScript types.
- *
- * | Type             | Support  | Remarks                                |
- * |------------------|----------|----------------------------------------|
- * | duk::Array       | is, push |                                        |
- * | duk::Function    | is, push | is just check if the value is callable |
- * | duk::FunctionMap | put      |                                        |
- * | duk::Global      | push     |                                        |
- * | duk::Null        | is, push |                                        |
- * | duk::Object      | is, push |                                        |
- * | duk::This        | push     |                                        |
- * | duk::Undefined   | is, push |                                        |
- *
- * ## Partial specializations
- *
- * These partial specializations will use complete specialization for T.
- *
- * | Type                               | Support   | Remarks                |
- * |------------------------------------|-----------|------------------------|
- * | std::unordered_map<std::string, T> | push, put | push or put properties |
- * | std::vector<T>                     | push, put | push array of values   |
- */
-
-/**
- * \page js-basics Basics
- * \brief Basics use case.
- *
- * The following topics are sample use case of the C++ front end. It does not use extended features that this module
- * provides.
- *
- *   - \subpage js-basics-t1
- *   - \subpage js-basics-t2
- *   - \subpage js-basics-t3
- */
-
-/**
- * \page js-basics-t1 Example 1: call JavaScript code from C++
- * \brief Evaluate JavaScript code from C++.
- *
- * Let use JavaScript to compute a simple expression.
- *
- * \code
- * #include "js.hpp"
- *
- * int main()
- * {
- *   duk::UniqueContext ctx;
- *
- *   duk::pevalString(ctx, "1 + 1");
- *   std::cout << duk::get<int>(ctx -1) << std::endl;
- *
- *   return 0;
- * }
- * \endcode
- */
-
-/**
- * \page js-basics-t2 Example 2: call C++ code from JavaScript
- * \brief Evaluate a function from JavaScript.
- *
- * In that example, we will add a C++ function to JavaScript and call it from the script. The function just compute the
- * two arguments that are passed through the function and return the result.
- *
- * We take the benefits of C++11 to map the function. The lambda can not have a capture because Duktape use raw C
- * function pointers and this module keep them.
- *
- * \code
- * #include "js.hpp"
- *
- * int main()
- * {
- *   duk::UniqueContext ctx;
- *
- *   // Push a function as global "add"
- *   duk::putGlobal(ctx, "add", duk::Function{[] (duk::Context *ctx) -> duk::Ret {
- *     int x = duk::require<int>(ctx, 0);
- *     int y = duk::require<int>(ctx, 1);
- *
- *     duk::push(ctx, x + y);
- *
- *     return 1;
- *   }, 2});
- *
- *   // Evaluate from JavaScript
- *   duk::pevalString(ctx, "add(1, 2)");
- *
- *   return 0;
- * }
- * \endcode
- *
- * Please note the **2** at end of lambda which indicates that the function takes 2 arguments. If number of arguments
- * is variadic, pass DUK_VARARGS there.
- */
-
-/**
- * \page js-basics-t3 Example 3: pushing and getting values
- * \brief Manage values between JavaScript and C++.
- *
- * As you have seen in the previous examples, we were pushing some values to the Duktape context.
- *
- * With the C Duktape frontend, you usually use duk_push_int, duk_push_string and all other related functions. The libjs
- * module provides an uniform and convenient way for sharing values with the same functions.
- *
- * See the description of duk::TypeTraits to see the supported types.
- *
- * ## Push
- *
- * The duk::push function is a template that accept most of the primitives types. It uses the specializations of the
- * duk::TypeTraits class (described later).
- *
- * Example of code
- *
- * \code
- * duk::push(ctx, 123); // an integer
- * duk::push(ctx, true); // a boolean
- * \endcode
- *
- * The push function add a new value to the stack for any specialization of TypeTraits provided by libjs.
- *
- * ## Get
- *
- * The duk::get function is similar to duk_get_ functions. It usually does not check the value and return a sane default
- * value.
- *
- * This template function does not take the template argument so it can't be deduced and must be specified explicitly.
- *
- * \code
- * duk::get<int>(ctx, 0) // get an int at index 0
- * duk::get<std::string>(ctx, 1) // get a std::string at index 1
- * \endcode
- *
- * ## Require
- *
- * The duk::require function is similar to duk_require functions. It requires the exact type at the given index. If the
- * value is invalid a JavaScript error is propagated.
- *
- * \code
- * duk::require<int>(ctx, 0) // require an int at index 0 or raise an error
- * \endcode
- *
- * ## Put
- *
- * This special function is similar to push except that it applies to the existing object at the top of the stack. It
- * is usually implemented for map and vector.
- *
- * \code
- * // Fill the object at the top of the stack with this map
- * std:unordered_map<std::string, int> map{
- *   { "value1", 1 },
- *   { "value2", 2 }
- * };
- *
- * duk::put(ctx, map);
- * \endcode
- *
- * ## Is
- *
- * This function duk::is checks if the value at the given index is of the given type and return true.
- *
- * Just like duk::get, this function need the explicit template parameter.
- *
- * \code
- * duk::push(ctx, 1);
- * duk::is<int>(ctx, -1); // true
- * \endcode
- *
- * ## Optional
- *
- * The duk::optional function has no equivalent in Duktape C API. It is a convenient way to get values with a default
- * replacement is not available.
- *
- * The common implementation uses duk::is and then duk::get.
- *
- * \code
- * duk::optional<int>(ctx, -1, 123); // 123 is -1 has no value or is not an int
- * \endcode
- */
-
-/**
- * \page js-more Extensions and advanced features.
- * \brief Evolved extensions provided by libjs.
- *
- * The following topics are provided by libjs and have no equivalent in Duktape C API.
- *
- * \subpage js-more-t1
- */
-
-/**
- * \page js-more-t1 Advanced 1: adding your own types to TypeTraits
- * \brief How to specialize duk::TypeTraits structure.
- *
- * This topic shows how you can specialize the duk::TypeTraits structure to add more types.
- *
- * Specializing the duk::TypeTraits is usually only needed when you want to convert a C++ object into JavaScript.
- *
- * In this example we will convert a C++ small structure containing two integers to JavaScript.
- *
- * \note It is not required to implement all functions from duk::TypeTraits. Just provide which one you need.
- *
- * ## The C++ structure
- *
- * The point does not have any methods, it just a description of two integers.
- *
- * \code
- * struct Point {
- *   int x;
- *   int y;
- * };
- * \endcode
- *
- * ## The push function
- *
- * Let's add a push function that will create a JavaScript object with **x** and **y** properties.
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static void push(Context *ctx, const Point &point)
- *   {
- *     // Create an object
- *     push(ctx, Object());
- *
- *     // Set x
- *     putProperty(ctx, -1, "x", point.x);
- *
- *     // Set y
- *     putProperty(ctx, -1, "y", point.y);
- *   }
- * };
- *
- * }
- * \endcode
- *
- * You can safely use different type of reference as second argument.
- *
- * That's it, you can now safely invoke `duk::push(ctx, Point{100, 200});`.
- *
- * ## The get function
- *
- * The get function usually return a new object. The recommandation is to provide sane defaults except if you have any
- * reason to not do so.
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static Point get(Context *ctx, Index index)
- *   {
- *     Point point{0, 0};
- *
- *     if (is<Object>(ctx, index)) {
- *       point.x = getProperty<int>(ctx, index, "x");
- *       point.y = getProperty<int>(ctx, index, "y");
- *     }
- *
- *     return point;
- *   }
- * };
- *
- * }
- * \endcode
- *
- * Now you can invoke `duk::get<Point>(ctx, 0)` to convert a JavaScript object to the Point structure.
- *
- * ## The require function
- *
- * The require function has the same signature as get. It's up to you to decide which criterias makes the object not
- * suitable for conversion.
- *
- * In that example, we will require that object at the index is a JavaScript object and that **x**, **y** are present.
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static Point require(Context *ctx, Index index)
- *   {
- *     Point point;
- *
- *     // Raise an error if not object
- *     if (!is<Object>(ctx, index))
- *       duk::raise(ctx, TypeError("object required"));
- *
- *     // Get x, for simplicity we just check that x and y exist.
- *     if (!hasProperty(ctx, index, "x"))
- *       duk::raise(ctx, TypeError("property x missing"));
- *
- *     // Get y
- *     if (!hasProperty(ctx, index, "y"))
- *       duk::raise(ctx, TypeError("property y missing"));
- *
- *     // Note: if you need more security, check that types are integers too.
- *     point.x = duk::getProperty<int>(ctx, index, "x");
- *     point.y = duk::getProperty<int>(ctx, index, "y");
- *
- *     return point;
- *   }
- * };
- *
- * }
- * \endcode
- *
- * ## The is function
- *
- * The is function returns a boolean. Again, you decide when the value is appropriate.
- *
- * \code
- *
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static bool is(Context *ctx, Index index)
- *   {
- *     return is<Object>(ctx, index) && hasProperty(ctx, index, "x") && hasProperty(ctx, index, "y");
- *   }
- * };
- *
- * }
- *
- * \endcode
- *
- * ## The optional function
- *
- * The optional function is like get, you should return a value when it is appropriate for conversion. The
- * recommandation is to return the default value **only if** there is no value at the given index or it it not
- * the correct type.
- *
- * Usual implementation looks like this:
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static Point optional(Context *ctx, Index index, Point def)
- *   {
- *     return is(ctx, index) ? get(ctx, index) : def;
- *   }
- * };
- *
- * }
- * \endcode
- */
-
-#include <cassert>
-#include <cstdio>
-#include <functional>
-#include <memory>
-#include <string>
-#include <type_traits>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include <duktape.h>
-
-namespace irccd {
-
-/**
- * Duktape C++ namespace wrapper.
- */
-namespace duk {
-
-/**
- * \brief Typedef without pointer.
- */
-using Context = ::duk_context;
-
-/**
- * \brief Typedef for duk_double_t.
- */
-using Double = ::duk_double_t;
-
-/**
- * \brief Typedef for duk_idx_t.
- */
-using Index = ::duk_idx_t;
-
-/**
- * \brief Typedef for duk_ret_t.
- */
-using Ret = ::duk_ret_t;
-
-/**
- * \brief Typedef for duk_size_t.
- */
-using Size = ::duk_size_t;
-
-/**
- * \brief Typedef for duk_int_t.
- */
-using Int = ::duk_int_t;
-
-/**
- * \brief Typedef for duk_uint_t;
- */
-using Uint = ::duk_uint_t;
-
-/**
- * \class StackAssert
- * \brief Stack sanity checker.
- *
- * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor
- * will examinate if the stack size matches the user expected size.
- *
- * When compiled with NDEBUG, this class does nothing.
- *
- * To use it, just declare an lvalue at the beginning of your function.
- */
-class StackAssert {
-#if !defined(NDEBUG)
-private:
-	Context *m_context;
-	unsigned m_expected;
-	unsigned m_begin;
-#endif
-
-public:
-	/**
-	 * Create the stack checker.
-	 *
-	 * No-op if NDEBUG is set.
-	 *
-	 * \param ctx the context
-	 * \param expected the size expected relative to the already existing values
-	 */
-	inline StackAssert(Context *ctx, unsigned expected = 0) noexcept
-#if !defined(NDEBUG)
-		: m_context(ctx)
-		, m_expected(expected)
-		, m_begin(static_cast<unsigned>(duk_get_top(ctx)))
-#endif
-	{
-#if defined(NDEBUG)
-		(void)ctx;
-		(void)expected;
-#endif
-	}
-
-	/**
-	 * Verify the expected size.
-	 *
-	 * No-op if NDEBUG is set.
-	 */
-	inline ~StackAssert() noexcept
-	{
-#if !defined(NDEBUG)
-		if (static_cast<unsigned>(duk_get_top(m_context)) - m_begin != m_expected) {
-			std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n");
-			std::fprintf(stderr, "  Size at start:            %u\n", m_begin);
-			std::fprintf(stderr, "  Size at end:              %d\n", duk_get_top(m_context));
-			std::fprintf(stderr, "  Expected (user):          %u\n", m_expected);
-			std::fprintf(stderr, "  Expected (adjusted):      %u\n", m_expected + m_begin);
-			std::fprintf(stderr, "  Number of stale values:   %u\n", duk_get_top(m_context) - m_begin - m_expected);
-			std::abort();
-		}
-#endif
-	}
-};
-
-/**
- * \class TypeTraits
- * \brief Type information to implement new types in JavaScript's context.
- *
- * %This class depending on your needs may have the following functions:
- *
- * ## Construct
- *
- * Used by duk::construct, the function must place the value as this binding when the Duktape C function is
- * new-constructed.
- *
- * \code
- * static void construct(Context *ctx, Type value);
- * \endcode
- *
- * ## Get
- *
- * Convert the value at the given index and return it. Should return default object if value is invalid.
- *
- * \code
- * static Type get(Context *ctx, int index);
- * \endcode
- *
- * ## Is
- *
- * Tells if the value at given index is of the requested type.
- *
- * \code
- * static bool is(Context *ctx, int index);
- * \endcode
- *
- * ## Optional
- *
- * Get the value at the given index or return the defaultValue.
- *
- * \code
- * static Type optional(Context *ctx, int index, Type defaultValue);
- * \endcode
- *
- * ## Push
- *
- * Push the value into the stack.
- *
- * \code
- * static void push(Context *ctx, Type value);
- * \endcode
- *
- * ## Put
- *
- * Apply the value to the object at the top of the stack.
- *
- * \code
- * static void put(Context *ctx, Type value);
- * \endcode
- *
- * ## Require
- *
- * Require a value at the given index.
- *
- * \code
- * static Type require(Context *ctx, int index);
- * \endcode
- *
- */
-template <typename Type>
-class TypeTraits;
-
-/**
- * \class Object
- * \brief Special type for duk::TypeTraits.
- */
-class Object {
-};
-
-/**
- * \class Array
- * \brief Special type for duk::TypeTraits.
- */
-class Array {
-};
-
-/**
- * \class Global
- * \brief Special type for duk::TypeTraits.
- */
-class Global {
-};
-
-/**
- * \class Undefined
- * \brief Special type for duk::TypeTraits.
- */
-class Undefined {
-};
-
-/**
- * \class Null
- * \brief Special type for duk::TypeTraits.
- */
-class Null {
-};
-
-/**
- * \class This
- * \brief Special type for duk::TypeTraits.
- */
-class This {
-};
-
-/**
- * \class Function
- * \brief Duktape/C function definition.
- *
- * This class wraps the std::function as a Duktape/C function by storing a copied pointer.
- */
-class Function {
-public:
-	/**
-	 * The function pointer, must not be null.
-	 */
-	duk_c_function function;
-
-	/**
-	 * Number of args that the function takes
-	 */
-	duk_idx_t nargs{0};
-
-	/**
-	 * Constructor for compatibility.
-	 *
-	 * \param f the function
-	 * \param n the number of arguments
-	 */
-	inline Function(duk_c_function f, duk_idx_t n = 0) noexcept
-		: function(f)
-		, nargs(n)
-	{
-	}
-};
-
-/**
- * \brief Map of functions.
- */
-using FunctionMap = std::unordered_map<std::string, Function>;
-
-/**
- * \brief Map of any type.
- */
-template <typename T>
-using Map = std::unordered_map<std::string, T>;
-
-/**
- * \class Exception
- * \brief Error description.
- *
- * This class fills the fields got in an Error object.
- */
-class Exception : public std::exception {
-public:
-	std::string name;		//!< name of error
-	std::string message;		//!< error message
-	std::string stack;		//!< stack if available
-	std::string fileName;		//!< filename if applicable
-	int lineNumber{0};		//!< line number if applicable
-
-	/**
-	 * Get the error message. This effectively returns message field.
-	 *
-	 * \return the message
-	 */
-	const char *what() const noexcept override
-	{
-		return message.c_str();
-	}
-};
-
-/**
- * \brief RAII based Duktape handler.
- *
- * This class is implicitly convertible to duk_context for convenience.
- */
-class UniqueContext {
-private:
-	using Deleter = void (*)(duk_context *);
-	using Handle = std::unique_ptr<duk_context, Deleter>;
-
-	Handle m_handle;
-
-	UniqueContext(const UniqueContext &) = delete;
-	UniqueContext &operator=(const UniqueContext &) = delete;
-
-public:
-	/**
-	 * Create default context.
-	 */
-	inline UniqueContext()
-		: m_handle(duk_create_heap_default(), duk_destroy_heap)
-	{
-	}
-
-	/**
-	 * Default move constructor.
-	 */
-	UniqueContext(UniqueContext &&) noexcept = default;
-
-	/**
-	 * Convert the context to the native Duktape/C type.
-	 *
-	 * \return the duk_context
-	 */
-	inline operator duk_context *() noexcept
-	{
-		return m_handle.get();
-	}
-
-	/**
-	 * Convert the context to the native Duktape/C type.
-	 *
-	 * \return the duk_context
-	 */
-	inline operator duk_context *() const noexcept
-	{
-		return m_handle.get();
-	}
-
-	/**
-	 * Default move assignment operator.
-	 *
-	 * \return this
-	 */
-	UniqueContext &operator=(Context &&) noexcept = delete;
-};
-
-/**
- * \name Duktape C functions
- * \brief The following functions are wrappers on top of the Duktape C functions.
- *
- * They are as close as possible to the original functions.
- */
-
-/**
- * \{
- */
-
-/**
- * Wrapper for [duk_allow](http://duktape.org/api.html#duk_allow).
- *
- * \param ctx the context
- * \param size the requested size
- * \return the pointer
- */
-inline void *alloc(Context *ctx, Size size)
-{
-	return duk_alloc(ctx, size);
-}
-
-/**
- * Wrapper for [duk_allow_raw](http://duktape.org/api.html#duk_allow_raw).
- *
- * \param ctx the context
- * \param size the requested size
- * \return the pointer
- */
-inline void *allocRaw(Context *ctx, Size size)
-{
-	return duk_alloc_raw(ctx, size);
-}
-
-/**
- * Wrapper for [duk_base64_decode](http://duktape.org/api.html#duk_base64_decode).
- *
- * \param ctx the context
- * \param index the index
- */
-inline void base64Decode(Context *ctx, Index index)
-{
-	duk_base64_decode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_base64_encode](http://duktape.org/api.html#duk_base64_encode).
- *
- * \param ctx the context
- * \param index the index
- * \return the base64 string
- */
-inline std::string base64Encode(Context *ctx, Index index)
-{
-	return duk_base64_encode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_call](http://duktape.org/api.html#duk_call).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void call(Context *ctx, Index nargs = 0)
-{
-	duk_call(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_call_method](http://duktape.org/api.html#duk_call_method).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void callMethod(Context *ctx, Index nargs = 0)
-{
-	duk_call_method(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_call_prop](http://duktape.org/api.html#duk_call_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param nargs the number of arguments
- */
-inline void callProperty(Context *ctx, Index index, Index nargs = 0)
-{
-	duk_call_prop(ctx, index, nargs);
-}
-
-/**
- * Wrapper for [duk_char_code_at](http://duktape.org/api.html#duk_char_code_at).
- *
- * \param ctx the context
- * \param index the index
- * \param charOffset the offset
- * \return the code point
- */
-inline duk_codepoint_t charCodeAt(Context *ctx, Index index, duk_size_t charOffset)
-{
-	return duk_char_code_at(ctx, index, charOffset);
-}
-
-/**
- * Wrapper for [duk_check_stack](http://duktape.org/api.html#duk_check_stack).
- *
- * \param ctx the context
- * \param extra the extra space
- * \return true if space is available
- */
-inline bool checkStack(Context *ctx, Index extra)
-{
-	return duk_check_stack(ctx, extra) != 0;
-}
-
-/**
- * Wrapper for [duk_check_stack_top](http://duktape.org/api.html#duk_check_stack_top).
- *
- * \param ctx the context
- * \param top the extra space
- * \return true if space is available
- */
-inline bool checkStackTop(Context *ctx, Index top)
-{
-	return duk_check_stack_top(ctx, top) != 0;
-}
-
-/**
- * Wrapper for [duk_check_type](http://duktape.org/api.html#duk_check_type).
- *
- * \param ctx the context
- * \param index the value index
- * \param type the desired type
- * \return true if object is given type
- */
-inline bool checkType(Context *ctx, Index index, int type)
-{
-	return duk_check_type(ctx, index, type) != 0;
-}
-
-/**
- * Wrapper for [duk_check_type_mask](http://duktape.org/api.html#duk_check_type_mask).
- *
- * \param ctx the context
- * \param index the value index
- * \param mask the desired mask
- * \return true if object is one of the type
- */
-inline bool checkTypeMask(Context *ctx, Index index, unsigned mask)
-{
-	return duk_check_type_mask(ctx, index, mask) != 0;
-}
-
-/**
- * Wrapper for [duk_compact](http://duktape.org/api.html#duk_compact).
- *
- * \param ctx the context
- * \param objIndex the object index
- */
-inline void compact(Context *ctx, Index objIndex)
-{
-	duk_compact(ctx, objIndex);
-}
-
-/**
- * Wrapper for [duk_concat](http://duktape.org/api.html#duk_concat).
- *
- * \param ctx the context
- * \param count the number of values
- */
-inline void concat(Context *ctx, Index count)
-{
-	duk_concat(ctx, count);
-}
-
-/**
- * Wrapper for [duk_copy](http://duktape.org/api.html#duk_copy).
- *
- * \param ctx the context
- * \param from the from index
- * \param to the destination
- */
-inline void copy(Context *ctx, Index from, Index to)
-{
-	duk_copy(ctx, from, to);
-}
-
-/**
- * Wrapper for [duk_new](http://duktape.org/api.html#duk_new).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void create(Context *ctx, int nargs = 0)
-{
-	duk_new(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_def_prop](http://duktape.org/api.html#duk_def_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param flags the flags
- */
-inline void defineProperty(Context *ctx, Index index, unsigned flags)
-{
-	duk_def_prop(ctx, index, flags);
-}
-
-/**
- * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \return true if deleted
- */
-inline bool deleteProperty(Context *ctx, Index index)
-{
-	return duk_del_prop(ctx, index) != 0;
-}
-
-/**
- * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param position the property index
- * \return true if deleted
- */
-inline bool deleteProperty(Context *ctx, Index index, unsigned position)
-{
-	return duk_del_prop_index(ctx, index, position) != 0;
-}
-
-/**
- * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \return true if deleted
- */
-inline bool deleteProperty(Context *ctx, Index index, const std::string &name)
-{
-	return duk_del_prop_string(ctx, index, name.c_str()) != 0;
-}
-
-/**
- * Wrapper for [duk_dup](http://duktape.org/api.html#duk_dup).
- *
- * \param ctx the context
- * \param index the value to copy
- */
-inline void dup(Context *ctx, int index = -1)
-{
-	duk_dup(ctx, index);
-}
-
-/**
- * Wrapper for [duk_equals](http://duktape.org/api.html#duk_equals).
- *
- * \param ctx the context
- * \param index1 the first value
- * \param index2 the second value
- * \return true if they equal
- */
-inline bool equals(Context *ctx, Index index1, Index index2)
-{
-	return duk_equals(ctx, index1, index2) != 0;
-}
-
-/**
- * Wrapper for [duk_eval](http://duktape.org/api.html#duk_eval).
- *
- * \param ctx the context
- */
-inline void eval(Context *ctx)
-{
-	duk_eval(ctx);
-}
-
-/**
- * Wrapper for [duk_eval_file](http://duktape.org/api.html#duk_eval_file).
- *
- * \param ctx the context
- * \param path the path
- * \param result true to get the result at the top of the stack
- */
-inline void evalFile(Context *ctx, const std::string &path, bool result = true)
-{
-	return result ? duk_eval_file(ctx, path.c_str()) : duk_eval_file_noresult(ctx, path.c_str());
-}
-
-/**
- * Wrapper for [duk_eval_string](http://duktape.org/api.html#duk_eval_string).
- *
- * \param ctx the context
- * \param src the source script
- * \param result true to get the result at the top of the stack
- */
-inline void evalString(Context *ctx, const std::string &src, bool result = true)
-{
-	return result ? duk_eval_string(ctx, src.c_str()) : duk_eval_string_noresult(ctx, src.c_str());
-}
-/**
- * Wrapper for [duk_gc](http://duktape.org/api.html#duk_gc).
- *
- * \param ctx the context
- * \param flags the flags
- */
-inline void gc(Context *ctx, unsigned flags = 0)
-{
-	duk_gc(ctx, flags);
-}
-
-/**
- * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \return true if has
- */
-inline bool hasProperty(Context *ctx, Index index)
-{
-	return duk_has_prop(ctx, index) != 0;
-}
-
-/**
- * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param position the property index
- * \return true if has
- */
-inline bool hasProperty(Context *ctx, Index index, unsigned position)
-{
-	return duk_has_prop_index(ctx, index, position) != 0;
-}
-
-/**
- * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \return true if has
- */
-inline bool hasProperty(Context *ctx, int index, const std::string &name)
-{
-	return duk_has_prop_string(ctx, index, name.c_str()) != 0;
-}
-
-/**
- * Wrapper for [duk_insert](http://duktape.org/api.html#duk_insert).
- *
- * \param ctx the context
- * \param to the destination
- * \note Wrapper of duk_insert
- */
-inline void insert(Context *ctx, Index to)
-{
-	duk_insert(ctx, to);
-}
-
-/**
- * Wrapper for [duk_instanceof](http://duktape.org/api.html#duk_instanceof).
- *
- * \param ctx the context
- * \param idx1 the value to test
- * \param idx2 the instance requested
- * \return true if idx1 is instance of idx2
- */
-inline bool instanceof(Context *ctx, Index idx1, Index idx2)
-{
-	return duk_instanceof(ctx, idx1, idx2) != 0;
-}
-
-/**
- * Wrapper for [duk_is_constructor_call](http://duktape.org/api.html#duk_is_constructor_call).
- *
- * \param ctx the context
- * \return true if it's a constructor call (new operator)
- */
-inline bool isConstructorCall(Context *ctx)
-{
-	return duk_is_constructor_call(ctx) != 0;
-}
-
-/**
- * Wrapper for [duk_join](http://duktape.org/api.html#duk_join).
- *
- * \param ctx the context
- * \param count the number of values
- */
-inline void join(Context *ctx, Index count)
-{
-	duk_join(ctx, count);
-}
-
-/**
- * Wrapper for [duk_json_decode](http://duktape.org/api.html#duk_json_decode).
- *
- * \param ctx the context
- * \param index the index
- */
-inline void jsonDecode(Context *ctx, Index index)
-{
-	duk_json_decode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_json_encode](http://duktape.org/api.html#duk_json_encode).
- *
- * \param ctx the context
- * \param index the index
- * \return the JSON string
- */
-inline std::string jsonEncode(Context *ctx, Index index)
-{
-	return duk_json_encode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_normalize_index](http://duktape.org/api.html#duk_normalize_index).
- *
- * \param ctx the context
- * \param index the index
- * \return the absolute index
- */
-inline Index normalizeIndex(Context *ctx, Index index)
-{
-	return duk_normalize_index(ctx, index);
-}
-
-/**
- * Wrapper for [duk_pcall](http://duktape.org/api.html#duk_pcall).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- * \return non zero on failure
- */
-inline int pcall(Context *ctx, Index nargs = 0)
-{
-	return duk_pcall(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_pcall_method](http://duktape.org/api.html#duk_pcall_method).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- * \return non zero on failure
- */
-inline int pcallMethod(Context *ctx, Index nargs = 0)
-{
-	return duk_pcall_method(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_pcall_prop](http://duktape.org/api.html#duk_pcall_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param nargs the number of arguments
- * \return non zero on failure
- */
-inline int pcallProperty(Context *ctx, Index index, Index nargs = 0)
-{
-	return duk_pcall_prop(ctx, index, nargs);
-}
-
-/**
- * Wrapper for [duk_peval](http://duktape.org/api.html#duk_peval).
- *
- * \param ctx the context
- * \return non zero on failure
- */
-inline int peval(Context *ctx)
-{
-	return duk_peval(ctx);
-}
-
-/**
- * Wrapper for [duk_peval_file](http://duktape.org/api.html#duk_peval_file).
- *
- * \param ctx the context
- * \param path the path
- * \param result true to get the result at the top of the stack
- * \return non zero on failure
- */
-inline int pevalFile(Context *ctx, const std::string &path, bool result = true)
-{
-	return result ? duk_peval_file(ctx, path.c_str()) : duk_peval_file_noresult(ctx, path.c_str());
-}
-
-/**
- * Wrapper for [duk_peval_string](http://duktape.org/api.html#duk_peval_string).
- *
- * \param ctx the context
- * \param src the source script
- * \param result true to get the result at the top of the stack
- * \return non zero on failure
- */
-inline int pevalString(Context *ctx, const std::string &src, bool result = true)
-{
-	return result ? duk_peval_string(ctx, src.c_str()) : duk_peval_string_noresult(ctx, src.c_str());
-}
-
-/**
- * Wrapper for [duk_pop_n](http://duktape.org/api.html#duk_pop_n).
- *
- * \param ctx the context
- * \param count the number of values to pop
- */
-inline void pop(Context *ctx, Index count = 1)
-{
-	duk_pop_n(ctx, count);
-}
-
-/**
- * Wrapper for [duk_put_prop](http://duktape.org/api.html#duk_put_prop).
- *
- * \param ctx the context
- * \param index the object index
- */
-inline void putProperty(Context *ctx, Index index)
-{
-	duk_put_prop(ctx, index);
-}
-
-/**
- * Wrapper for [duk_put_prop_string](http://duktape.org/api.html#duk_put_prop_string).
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- */
-inline void putProperty(Context *ctx, Index index, const std::string &name)
-{
-	duk_put_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Wrapper for [duk_put_prop_index](http://duktape.org/api.html#duk_put_prop_index).
- *
- * \param ctx the context
- * \param index the object index
- * \param position the array position
- */
-inline void putProperty(Context *ctx, Index index, unsigned position)
-{
-	duk_put_prop_index(ctx, index, position);
-}
-
-/**
- * Wrapper for [duk_remove](http://duktape.org/api.html#duk_remove).
- *
- * \param ctx the context
- * \param index the value to remove
- */
-inline void remove(Context *ctx, Index index)
-{
-	duk_remove(ctx, index);
-}
-
-/**
- * Wrapper for [duk_replace](http://duktape.org/api.html#duk_replace).
- *
- * \param ctx the context
- * \param index the value to replace by the value at the top of the stack
- */
-inline void replace(Context *ctx, Index index)
-{
-	duk_replace(ctx, index);
-}
-
-/**
- * Wrapper for [duk_set_finalizer](http://duktape.org/api.html#duk_set_finalizer).
- *
- * \param ctx the context
- * \param index the value index
- */
-inline void setFinalizer(Context *ctx, Index index)
-{
-	duk_set_finalizer(ctx, index);
-}
-
-/**
- * Wrapper for [duk_set_prototype](http://duktape.org/api.html#duk_set_prototype).
- *
- * \param ctx the context
- * \param index the value index
- */
-inline void setPrototype(Context *ctx, Index index)
-{
-	duk_set_prototype(ctx, index);
-}
-
-/**
- * Wrapper for [duk_swap](http://duktape.org/api.html#duk_swap).
- *
- * \param ctx the context
- * \param index1 the first index
- * \param index2 the second index
- */
-inline void swap(Context *ctx, Index index1, Index index2)
-{
-	duk_swap(ctx, index1, index2);
-}
-
-/**
- * Wrapper for [duk_swap_top](http://duktape.org/api.html#duk_swap_top).
- *
- * \param ctx the context
- * \param index the index
- */
-inline void swapTop(Context *ctx, Index index)
-{
-	duk_swap_top(ctx, index);
-}
-
-/**
- * Wrapper for [duk_get_top](http://duktape.org/api.html#duk_get_top).
- *
- * \param ctx the context
- * \return the stack size
- */
-inline int top(Context *ctx)
-{
-	return duk_get_top(ctx);
-}
-
-/**
- * Wrapper for [duk_throw](http://duktape.org/api.html#duk_throw).
- *
- * \param ctx the context
- */
-inline void raise(Context *ctx)
-{
-	duk_throw(ctx);
-}
-
-/**
- *Wrapper for [duk_error](http://duktape.org/api.html#duk_error).
- *
- * \param ctx the context
- * \param type the error type (e.g. DUK_ERR_REFERENCE_ERROR)
- * \param fmt the format string
- * \param args the arguments
- */
-template <typename... Args>
-inline void raise(Context *ctx, int type, const char *fmt, Args&&... args)
-{
-	duk_error(ctx, type, fmt, std::forward<Args>(args)...);
-}
-
-/**
- * Wrapper for [duk_get_type](http://duktape.org/api.html#duk_get_type).
- *
- * \param ctx the context
- * \param index the index
- * \return the type
- */
-inline int type(Context *ctx, Index index)
-{
-	return duk_get_type(ctx, index);
-}
-
-/**
- * \}
- */
-
-/**
- * \name Extended functions
- * \brief Extended functions for libjs.
- *
- * The following functions are largely modified or extensions to Duktape.
- */
-
-/**
- * \{
- */
-
-/**
- * Get the error object when a JavaScript error has been thrown (e.g. eval failure).
- *
- * \param ctx the context
- * \param index the index
- * \param pop if true, also remove the exception from the stack
- * \return the information
- */
-inline Exception exception(Context *ctx, int index, bool pop = true)
-{
-	Exception ex;
-
-	index = duk_normalize_index(ctx, index);
-
-	duk_get_prop_string(ctx, index, "name");
-	ex.name = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "message");
-	ex.message = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "fileName");
-	ex.fileName = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "lineNumber");
-	ex.lineNumber = duk_to_int(ctx, -1);
-	duk_get_prop_string(ctx, index, "stack");
-	ex.stack = duk_to_string(ctx, -1);
-	duk_pop_n(ctx, 5);
-
-	if (pop)
-		duk_remove(ctx, index);
-
-	return ex;
-}
-
-/**
- * Push a value into the stack. Calls TypeTraits<T>::push(ctx, value);
- *
- * \param ctx the context
- * \param value the value to forward
- */
-template <typename Type>
-inline void push(Context *ctx, Type &&value)
-{
-	TypeTraits<std::decay_t<Type>>::push(ctx, std::forward<Type>(value));
-}
-
-/**
- * Put the value to the object at the top of the stack. Calls TypeTraits<T>::put(ctx, value);
- *
- * \param ctx the context
- * \param value the value to apply
- */
-template <typename Type>
-inline void put(Context *ctx, Type &&value)
-{
-	TypeTraits<std::decay_t<Type>>::put(ctx, std::forward<Type>(value));
-}
-
-/**
- * Generic template function to get a value from the stack.
- *
- * \param ctx the context
- * \param index the index
- * \return the value
- */
-template <typename Type>
-inline auto get(Context *ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0))
-{
-	return TypeTraits<Type>::get(ctx, index);
-}
-
-/**
- * Require a type at the specified index.
- *
- * \param ctx the context
- * \param index the index
- * \return the value
- */
-template <typename Type>
-inline auto require(Context *ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0))
-{
-	return TypeTraits<Type>::require(ctx, index);
-}
-
-/**
- * Check if a value is a type of T.
- *
- * The TypeTraits<T> must have `static bool is(ContextPtr ptr, int index)`.
- *
- * \param ctx the context
- * \param index the value index
- * \return true if is the type
- */
-template <typename T>
-inline bool is(Context *ctx, int index)
-{
-	return TypeTraits<T>::is(ctx, index);
-}
-
-/**
- * Get an optional value from the stack, if the value is not available of not the correct type,
- * return defaultValue instead.
- *
- * The TypeTraits<T> must have `static T optional(Context &, int index, T &&defaultValue)`.
- *
- * \param ctx the context
- * \param index the value index
- * \param defaultValue the value replacement
- * \return the value or defaultValue
- */
-template <typename Type>
-inline auto optional(Context *ctx, int index, Type &&defaultValue)
-{
-	return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue));
-}
-
-/**
- * Get the property `name' as value from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \return the value
- * \note The stack is unchanged
- */
-template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr>
-inline auto getProperty(Context *ctx, int index, const std::string &name) -> decltype(get<Type>(ctx, 0))
-{
-	duk_get_prop_string(ctx, index, name.c_str());
-	decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Get a property by index, for arrays.
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position int the object
- * \return the value
- * \note The stack is unchanged
- */
-template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr>
-inline auto getProperty(Context *ctx, int index, int position) -> decltype(get<Type>(ctx, 0))
-{
-	duk_get_prop_index(ctx, index, position);
-	decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Get the property `name' and push it to the stack from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \note The stack contains the property value
- */
-template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr>
-inline void getProperty(Context *ctx, int index, const std::string &name)
-{
-	duk_get_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Get the property by index and push it to the stack from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position in the object
- * \note The stack contains the property value
- */
-template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr>
-inline void getProperty(Context *ctx, int index, int position)
-{
-	duk_get_prop_index(ctx, index, position);
-}
-
-/**
- * Get an optional property `name` from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \param def the default value
- * \return the value or def
- * \note The stack is unchanged
- */
-template <typename Type, typename DefaultValue>
-inline auto optionalProperty(Context *ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def)))
-{
-	duk_get_prop_string(ctx, index, name.c_str());
-	decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def));
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Get an optional property by index, for arrays
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position int the object
- * \param def the default value
- * \return the value or def
- * \note The stack is unchanged
- */
-template <typename Type, typename DefaultValue>
-inline auto optionalProperty(Context *ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def)))
-{
-	duk_get_prop_index(ctx, index, position);
-	decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def));
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Set a property to the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \param value the value to forward
- * \note The stack is unchanged
- */
-template <typename Type>
-void putProperty(Context *ctx, int index, const std::string &name, Type &&value)
-{
-	index = duk_normalize_index(ctx, index);
-
-	push(ctx, std::forward<Type>(value));
-	duk_put_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Set a property by index, for arrays.
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position in the object
- * \param value the value to forward
- * \note The stack is unchanged
- */
-template <typename Type>
-void putProperty(Context *ctx, int index, int position, Type &&value)
-{
-	index = duk_normalize_index(ctx, index);
-
-	push(ctx, std::forward<Type>(value));
-	duk_put_prop_index(ctx, index, position);
-}
-
-/**
- * Get a global value.
- *
- * \param ctx the context
- * \param name the name of the global variable
- * \return the value
- */
-template <typename Type>
-inline auto getGlobal(Context *ctx, const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(ctx, 0))
-{
-	duk_get_global_string(ctx, name.c_str());
-	decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Overload that push the value at the top of the stack instead of returning it.
- *
- * \param ctx the context
- * \param name the name of the global variable
- */
-template <typename Type>
-inline void getGlobal(Context *ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr)
-{
-	duk_get_global_string(ctx, name.c_str());
-}
-
-/**
- * Set a global variable.
- *
- * \param ctx the context
- * \param name the name of the global variable
- * \param type the value to set
- */
-template <typename Type>
-inline void putGlobal(Context *ctx, const std::string &name, Type&& type)
-{
-	push(ctx, std::forward<Type>(type));
-	duk_put_global_string(ctx, name.c_str());
-}
-
-/**
- * Put the value at the top of the stack as global property.
- *
- * \param ctx the context
- * \param name the property name
- */
-inline void putGlobal(Context *ctx, const std::string &name)
-{
-	duk_put_global_string(ctx, name.c_str());
-}
-
-/**
- * Enumerate an object or an array at the specified index.
- *
- * \param ctx the context
- * \param index the object or array index
- * \param flags the optional flags to pass to duk_enum
- * \param getvalue set to true if you want to extract the value
- * \param func the function to call for each properties
- */
-template <typename Func>
-void enumerate(Context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
-{
-	duk_enum(ctx, index, flags);
-
-	while (duk_next(ctx, -1, getvalue)) {
-		func(ctx);
-		duk_pop_n(ctx, 1 + (getvalue ? 1 : 0));
-	}
-
-	duk_pop(ctx);
-}
-
-/**
- * Return the this binding of the current function.
- *
- * \param ctx the context
- * \return the this binding as the template given
- */
-template <typename T>
-inline auto self(Context *ctx) -> decltype(TypeTraits<T>::require(ctx, 0))
-{
-	duk_push_this(ctx);
-	decltype(TypeTraits<T>::require(ctx, 0)) value = TypeTraits<T>::require(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Throw an ECMAScript exception.
- *
- * \param ctx the context
- * \param ex the exception
- */
-template <typename Exception>
-void raise(Context *ctx, const Exception &ex)
-{
-	ex.raise(ctx);
-}
-
-/**
- * Construct the object in place, setting value as this binding.
- *
- * The TypeTraits<T> must have the following requirements:
- *
- * - static void construct(Context &, T): must update this with the value and keep the stack unchanged
- *
- * \param ctx the context
- * \param value the value to forward
- * \see self
- */
-template <typename T>
-inline void construct(Context *ctx, T &&value)
-{
-	TypeTraits<std::decay_t<T>>::construct(ctx, std::forward<T>(value));
-}
-
-/**
- * \}
- */
-
-/**
- * \class Error
- * \brief Base ECMAScript error class.
- * \warning Override the function create for your own exceptions
- */
-class Error {
-private:
-	int m_type{DUK_ERR_ERROR};
-	std::string m_message;
-
-protected:
-	/**
-	 * Constructor with a type of error specified, specially designed for derived errors.
-	 *
-	 * \param type of error (e.g. DUK_ERR_ERROR)
-	 * \param message the message
-	 */
-	inline Error(int type, std::string message) noexcept
-		: m_type(type)
-		, m_message(std::move(message))
-	{
-	}
-
-public:
-	/**
-	 * Constructor with a message.
-	 *
-	 * \param message the message
-	 */
-	inline Error(std::string message) noexcept
-		: m_message(std::move(message))
-	{
-	}
-
-	/**
-	 * Create the exception on the stack.
-	 *
-	 * \note the default implementation search for the global variables
-	 * \param ctx the context
-	 */
-	virtual void raise(Context *ctx) const
-	{
-		duk_error(ctx, m_type, "%s", m_message.c_str());
-	}
-};
-
-/**
- * \class EvalError
- * \brief Error in eval() function.
- */
-class EvalError : public Error {
-public:
-	/**
-	 * Construct an EvalError.
-	 *
-	 * \param message the message
-	 */
-	inline EvalError(std::string message) noexcept
-		: Error(DUK_ERR_EVAL_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class RangeError
- * \brief Value is out of range.
- */
-class RangeError : public Error {
-public:
-	/**
-	 * Construct an RangeError.
-	 *
-	 * \param message the message
-	 */
-	inline RangeError(std::string message) noexcept
-		: Error(DUK_ERR_RANGE_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class ReferenceError
- * \brief Trying to use a variable that does not exist.
- */
-class ReferenceError : public Error {
-public:
-	/**
-	 * Construct an ReferenceError.
-	 *
-	 * \param message the message
-	 */
-	inline ReferenceError(std::string message) noexcept
-		: Error(DUK_ERR_REFERENCE_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class SyntaxError
- * \brief Syntax error in the script.
- */
-class SyntaxError : public Error {
-public:
-	/**
-	 * Construct an SyntaxError.
-	 *
-	 * \param message the message
-	 */
-	inline SyntaxError(std::string message) noexcept
-		: Error(DUK_ERR_SYNTAX_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class TypeError
- * \brief Invalid type given.
- */
-class TypeError : public Error {
-public:
-	/**
-	 * Construct an TypeError.
-	 *
-	 * \param message the message
-	 */
-	inline TypeError(std::string message) noexcept
-		: Error(DUK_ERR_TYPE_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class URIError
- * \brief URI manipulation failure.
- */
-class URIError : public Error {
-public:
-	/**
-	 * Construct an URIError.
-	 *
-	 * \param message the message
-	 */
-	inline URIError(std::string message) noexcept
-		: Error(DUK_ERR_URI_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class TypeTraits<int>
- * \brief Default implementation for int.
- *
- * Provides: get, is, optional, push, require.
- */
-template <>
-class TypeTraits<int> {
-public:
-	/**
-	 * Get an integer, return 0 if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline int get(Context *ctx, int index)
-	{
-		return duk_get_int(ctx, index);
-	}
-
-	/**
-	 * Check if value is an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if integer
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_number(ctx, index) != 0;
-	}
-
-	/**
-	 * Get an integer, return defaultValue if the value is not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the integer or defaultValue
-	 */
-	static inline int optional(Context *ctx, int index, int defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push an integer.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, int value)
-	{
-		duk_push_int(ctx, value);
-	}
-
-	/**
-	 * Require an integer, throws a JavaScript exception if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline int require(Context *ctx, int index)
-	{
-		return duk_require_int(ctx, index);
-	}
-};
-
-/**
- * \class TypeTraits<bool>
- * \brief Default implementation for bool.
- *
- * Provides: get, is, optional, push, require.
- */
-template <>
-class TypeTraits<bool> {
-public:
-	/**
-	 * Get a boolean, return 0 if not a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the boolean
-	 */
-	static inline bool get(Context *ctx, int index)
-	{
-		return duk_get_boolean(ctx, index) != 0;
-	}
-
-	/**
-	 * Check if value is a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if boolean
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_boolean(ctx, index) != 0;
-	}
-
-	/**
-	 * Get a bool, return defaultValue if the value is not a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the boolean or defaultValue
-	 */
-	static inline bool optional(Context *ctx, int index, bool defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a boolean.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, bool value)
-	{
-		duk_push_boolean(ctx, value);
-	}
-
-	/**
-	 * Require a boolean, throws a JavaScript exception if not a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the boolean
-	 */
-	static inline bool require(Context *ctx, int index)
-	{
-		return duk_require_boolean(ctx, index) != 0;
-	}
-};
-
-/**
- * \class TypeTraits<double>
- * \brief Default implementation for double.
- *
- * Provides: get, is, optional, push, require.
- */
-template <>
-class TypeTraits<double> {
-public:
-	/**
-	 * Get a double, return 0 if not a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the double
-	 */
-	static inline double get(Context *ctx, int index)
-	{
-		return duk_get_number(ctx, index);
-	}
-
-	/**
-	 * Check if value is a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if double
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_number(ctx, index) != 0;
-	}
-
-	/**
-	 * Get a double, return defaultValue if the value is not a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the double or defaultValue
-	 */
-	static inline double optional(Context *ctx, int index, double defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a double.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, double value)
-	{
-		duk_push_number(ctx, value);
-	}
-
-	/**
-	 * Require a double, throws a JavaScript exception if not a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the double
-	 */
-	static inline double require(Context *ctx, int index)
-	{
-		return duk_require_number(ctx, index);
-	}
-};
-
-/**
- * \class TypeTraits<std::string>
- * \brief Default implementation for std::string.
- *
- * Provides: get, is, optional, push, require.
- *
- * Note: the functions allows embedded '\0'.
- */
-template <>
-class TypeTraits<std::string> {
-public:
-	/**
-	 * Get a string, return 0 if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline std::string get(Context *ctx, int index)
-	{
-		duk_size_t size;
-		const char *text = duk_get_lstring(ctx, index, &size);
-
-		return std::string{text, size};
-	}
-
-	/**
-	 * Check if value is a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if string
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_string(ctx, index) != 0;
-	}
-
-	/**
-	 * Get a string, return defaultValue if the value is not an string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the string or defaultValue
-	 */
-	static inline std::string optional(Context *ctx, int index, std::string defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a string.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, const std::string &value)
-	{
-		duk_push_lstring(ctx, value.c_str(), value.length());
-	}
-
-	/**
-	 * Require a string, throws a JavaScript exception if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline std::string require(Context *ctx, int index)
-	{
-		duk_size_t size;
-		const char *text = duk_require_lstring(ctx, index, &size);
-
-		return std::string{text, size};
-	}
-};
-
-/**
- * \class TypeTraits<const char *>
- * \brief Default implementation for const char literals.
- *
- * Provides: get, is, optional, push, require.
- */
-template <>
-class TypeTraits<const char *> {
-public:
-	/**
-	 * Get a string, return 0 if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline const char *get(Context *ctx, int index)
-	{
-		return duk_get_string(ctx, index);
-	}
-
-	/**
-	 * Check if value is a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if string
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_string(ctx, index) != 0;
-	}
-
-	/**
-	 * Get an integer, return defaultValue if the value is not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the integer or defaultValue
-	 */
-	static inline const char *optional(Context *ctx, int index, const char *defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a string.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, const char *value)
-	{
-		duk_push_string(ctx, value);
-	}
-
-	/**
-	 * Require a string, throws a JavaScript exception if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline const char *require(Context *ctx, int index)
-	{
-		return duk_require_string(ctx, index);
-	}
-};
-
-/**
- * \class TypeTraits<unsigned>
- * \brief Default implementation for unsigned.
- *
- * Provides: get, is, optional, push, require.
- */
-template <>
-class TypeTraits<unsigned> {
-public:
-	/**
-	 * Get an integer, return 0 if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline unsigned get(Context *ctx, int index)
-	{
-		return duk_get_uint(ctx, index);
-	}
-
-	/**
-	 * Check if value is an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if integer
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_number(ctx, index) != 0;
-	}
-
-	/**
-	 * Get an integer, return defaultValue if the value is not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the integer or defaultValue
-	 */
-	static inline unsigned optional(Context *ctx, int index, unsigned defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push an integer.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, unsigned value)
-	{
-		duk_push_uint(ctx, value);
-	}
-
-	/**
-	 * Require an integer, throws a JavaScript exception if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline unsigned require(Context *ctx, int index)
-	{
-		return duk_require_uint(ctx, index);
-	}
-};
-
-/**
- * \brief Implementation for non-managed pointers.
- *
- * Provides: get, is, optional, push, require.
- */
-template <typename T>
-class TypeTraits<T *> {
-public:
-	/**
-	 * Get a pointer, return nullptr if not a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the pointer
-	 */
-	static inline T *get(Context *ctx, int index)
-	{
-		return static_cast<T *>(duk_to_pointer(ctx, index));
-	}
-
-	/**
-	 * Check if value is a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if pointer
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_pointer(ctx, index) != 0;
-	}
-
-	/**
-	 * Get a pointer, return defaultValue if the value is not a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the pointer or defaultValue
-	 */
-	static inline T *optional(Context *ctx, int index, T *defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a pointer.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, T *value)
-	{
-		duk_push_pointer(ctx, value);
-	}
-
-	/**
-	 * Require a pointer, throws a JavaScript exception if not a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the pointer
-	 */
-	static inline T *require(Context *ctx, int index)
-	{
-		return static_cast<T *>(duk_require_pointer(ctx, index));
-	}
-};
-
-/**
- * \class TypeTraits<Function>
- * \brief Push C++ function to the stack.
- *
- * Provides: push.
- *
- * This implementation push a Duktape/C function that is wrapped as C++ for convenience.
- */
-template <>
-class TypeTraits<Function> {
-public:
-	/**
-	 * Check if the value at the given index is callable.
-	 *
-	 * \param ctx the context
-	 * \param index the value index
-	 * \return true if the value is callable
-	 */
-	static bool is(Context *ctx, Index index)
-	{
-		return duk_is_callable(ctx, index) != 0;
-	}
-
-	/**
-	 * Push the C++ function, it is wrapped as Duktape/C function and allocated on the heap by moving the
-	 * std::function.
-	 *
-	 * \param ctx the context
-	 * \param fn the function
-	 */
-	static void push(Context *ctx, Function fn)
-	{
-		duk_push_c_function(ctx, fn.function, fn.nargs);
-	}
-};
-
-/**
- * \class TypeTraits<FunctionMap>
- * \brief Put the functions to the object at the top of the stack.
- *
- * Provides: put.
- */
-template <>
-class TypeTraits<FunctionMap> {
-public:
-	/**
-	 * Push all functions to the object at the top of the stack.
-	 *
-	 * \param ctx the context
-	 * \param map the map of function
-	 */
-	static void put(Context *ctx, const FunctionMap &map)
-	{
-		StackAssert sa(ctx, 0);
-
-		for (const auto &entry : map) {
-			duk_push_c_function(ctx, entry.second.function, entry.second.nargs);
-			duk_put_prop_string(ctx, -2, entry.first.c_str());
-		}
-	}
-};
-
-/**
- * \class TypeTraits<Object>
- * \brief Push empty object to the stack.
- *
- * Provides: is, push.
- */
-template <>
-class TypeTraits<Object> {
-public:
-	/**
-	 * Check if value is an object.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if object
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_object(ctx, index) != 0;
-	}
-
-	/**
-	 * Create an empty object on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Object &)
-	{
-		duk_push_object(ctx);
-	}
-};
-
-/**
- * \class TypeTraits<Array>
- * \brief Push empty array to the stack.
- *
- * Provides: is, push.
- */
-template <>
-class TypeTraits<Array> {
-public:
-	/**
-	 * Check if value is a array.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if array
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_array(ctx, index) != 0;
-	}
-
-	/**
-	 * Create an empty array on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Array &)
-	{
-		duk_push_array(ctx);
-	}
-};
-
-/**
- * \class TypeTraits<Undefined>
- * \brief Push undefined value to the stack.
- *
- * Provides: is, push.
- */
-template <>
-class TypeTraits<Undefined> {
-public:
-	/**
-	 * Check if value is undefined.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if undefined
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_undefined(ctx, index) != 0;
-	}
-
-	/**
-	 * Push undefined value on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Undefined &)
-	{
-		duk_push_undefined(ctx);
-	}
-};
-
-/**
- * \class TypeTraits<Null>
- * \brief Push null value to the stack.
- *
- * Provides: is, push.
- */
-template <>
-class TypeTraits<Null> {
-public:
-	/**
-	 * Check if value is null.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if null
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_null(ctx, index) != 0;
-	}
-
-	/**
-	 * Push null value on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Null &)
-	{
-		duk_push_null(ctx);
-	}
-};
-
-/**
- * \brief Push this binding into the stack.
- *
- * Provides: push.
- */
-template <>
-class TypeTraits<This> {
-public:
-	/**
-	 * Push this function into the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const This &)
-	{
-		duk_push_this(ctx);
-	}
-};
-
-/**
- * \class TypeTraits<Global>
- * \brief Push the global object to the stack.
- *
- * Provides: push.
- */
-template <>
-class TypeTraits<Global> {
-public:
-	/**
-	 * Push the global object into the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Global &)
-	{
-		duk_push_global_object(ctx);
-	}
-};
-
-/**
- * \brief Push a map of key-value pair as objects.
- *
- * Provides: push, put.
- *
- * This class is convenient for settings constants such as enums, string and such.
- */
-template <typename T>
-class TypeTraits<std::unordered_map<std::string, T>> {
-public:
-	/**
-	 * Put all values from the map as properties to the object at the top of the stack.
-	 *
-	 * \param ctx the context
-	 * \param map the values
-	 * \note You need an object at the top of the stack before calling this function
-	 */
-	static void push(Context *ctx, const std::unordered_map<std::string, T> &map)
-	{
-		StackAssert sa(ctx, 1);
-
-		duk_push_object(ctx);
-		put(ctx, map);
-	}
-
-	/**
-	 * Apply the map to the object at the top of the stack.
-	 *
-	 * \pre top value must be an object
-	 * \param ctx the context
-	 * \param map the map
-	 */
-	static void put(Context *ctx, const std::unordered_map<std::string, T> &map)
-	{
-		assert(type(ctx, -1) == DUK_TYPE_OBJECT);
-
-		StackAssert sa(ctx);
-
-		for (const auto &pair : map) {
-			TypeTraits<T>::push(ctx, pair.second);
-			duk_put_prop_string(ctx, -2, pair.first.c_str());
-		}
-	}
-};
-
-/**
- * \brief Push or get vectors as JavaScript arrays.
- *
- * Provides: get, push, put.
- */
-template <typename T>
-class TypeTraits<std::vector<T>> {
-public:
-	/**
-	 * Get an array from the stack.
-	 *
-	 * \param ctx the context
-	 * \param index the array index
-	 * \return the array or empty array if the value is not an array
-	 */
-	static std::vector<T> get(Context *ctx, int index)
-	{
-		StackAssert sa(ctx, 0);
-
-		std::vector<T> result;
-
-		if (!duk_is_array(ctx, -1))
-			return result;
-
-		size_t total = duk_get_length(ctx, index);
-
-		for (size_t i = 0; i < total; ++i)
-			result.push_back(getProperty<T>(ctx, index, static_cast<int>(i)));
-
-		return result;
-	}
-
-	/**
-	 * Create an array with the specified values.
-	 *
-	 * \param ctx the context
-	 * \param array the values
-	 */
-	static void push(Context *ctx, const std::vector<T> &array)
-	{
-		StackAssert sa(ctx, 1);
-
-		duk_push_array(ctx);
-		put(ctx, array);
-	}
-
-	/**
-	 * Apply the array to the object at the top of the stack.
-	 *
-	 * \pre top value must be an object
-	 * \param ctx the context
-	 * \param array the array
-	 */
-	static void put(Context *ctx, const std::vector<T> &array)
-	{
-		assert(type(ctx, -1) == DUK_TYPE_OBJECT);
-
-		StackAssert sa(ctx);
-
-		unsigned i = 0;
-		for (const auto &v : array) {
-			TypeTraits<T>::push(ctx, v);
-			duk_put_prop_index(ctx, -2, i++);
-		}
-	}
-};
-
-} // !duk
-
-} // !irccd
-
-#endif // !IRCCD_JS_HPP
--- a/lib/irccd/mod-directory.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-directory.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -24,8 +24,8 @@
 #include <stdexcept>
 #include <string>
 
+#include "duktape.hpp"
 #include "fs.hpp"
-#include "js.hpp"
 #include "mod-directory.hpp"
 #include "mod-irccd.hpp"
 #include "path.hpp"
@@ -36,27 +36,26 @@
 
 namespace {
 
-std::string path(duk::Context *ctx)
+std::string path(duk_context *ctx)
 {
-	duk::push(ctx, duk::This{});
-	duk::getProperty<void>(ctx, -1, "path");
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, "path");
 
-	if (duk::type(ctx, -1) != DUK_TYPE_STRING)
-		duk::raise(ctx, duk::TypeError("invalid this binding"));
+	if (duk_get_type(ctx, -1) != DUK_TYPE_STRING)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object");
 
-	std::string ret = duk::get<std::string>(ctx, -1);
+	auto ret = duk_get_stdstring(ctx, -1);
 
 	if (ret.empty())
-		duk::raise(ctx, duk::TypeError("invalid directory with empty path"));
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path");
 
-	duk::pop(ctx, 2);
+	duk_pop_n(ctx, 2);
 
 	return ret;
 }
 
 /*
- * Find an entry recursively (or not) in a directory using a predicate
- * which can be used to test for regular expression, equality.
+ * Find an entry recursively (or not) in a directory using a predicate which can be used to test for regular expression, equality.
  *
  * Do not use this function directly, use:
  *
@@ -124,35 +123,37 @@
  *
  * The patternIndex is the argument where to test if the argument is a regex or a string.
  */
-duk::Ret find(duk::Context *ctx, std::string base, bool recursive, int patternIndex)
+duk_ret_t find(duk_context *ctx, std::string base, bool recursive, int patternIndex)
 {
 	base = path::clean(base);
 
 	try {
 		std::string path;
 
-		if (duk::is<std::string>(ctx, patternIndex))
-			path = findName(base, duk::get<std::string>(ctx, patternIndex), recursive);
+		if (duk_is_string(ctx, patternIndex))
+			path = findName(base, duk_get_string(ctx, patternIndex), recursive);
 		else {
 			// Check if it's a valid RegExp object.
-			duk::getGlobal<void>(ctx, "RegExp");
-
-			bool isRegex = duk::instanceof(ctx, patternIndex, -1);
+			duk_get_global_string(ctx, "RegExp");
+			auto isRegex = duk_instanceof(ctx, patternIndex, -1);
+			duk_pop(ctx);
 
-			duk::pop(ctx);
+			if (isRegex) {
+				duk_get_prop_string(ctx, patternIndex, "source");
+				auto pattern = duk_to_string(ctx, -1);
+				duk_pop(ctx);
 
-			if (isRegex)
-				path = findRegex(base, duk::getProperty<std::string>(ctx, patternIndex, "source"), recursive);
-			else
-				duk::raise(ctx, duk::TypeError("pattern must be a string or a regex expression"));
+				path = findRegex(base, pattern, recursive);
+			} else
+				duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern must be a string or a regex expression");
 		}
 
 		if (path.empty())
 			return 0;
 
-		duk::push(ctx, path);
+		duk_push_stdstring(ctx, path);
 	} catch (const std::exception &ex) {
-		duk::raise(ctx, duk::Error(ex.what()));
+		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
 	}
 
 	return 1;
@@ -164,10 +165,10 @@
  * - Directory.remove
  * - Directory.prototype.remove
  */
-duk::Ret remove(duk::Context *ctx, const std::string &path, bool recursive)
+duk_ret_t remove(duk_context *ctx, const std::string &path, bool recursive)
 {
 	if (!fs::isDirectory(path))
-		duk::raise(ctx, SystemError(EINVAL, "not a directory"));
+		duk_throw(ctx, SystemError(EINVAL, "not a directory"));
 
 	if (!recursive) {
 #if defined(_WIN32)
@@ -196,9 +197,9 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodFind(duk::Context *ctx)
+duk_ret_t methodFind(duk_context *ctx)
 {
-	return find(ctx, path(ctx), duk::optional<bool>(ctx, 1, false), 0);
+	return find(ctx, path(ctx), duk_get_boolean(ctx, 1), 0);
 }
 
 /*
@@ -213,19 +214,21 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodRemove(duk::Context *ctx)
+duk_ret_t methodRemove(duk_context *ctx)
 {
-	return remove(ctx, path(ctx), duk::optional<bool>(ctx, 0, false));
+	return remove(ctx, path(ctx), duk_get_boolean(ctx, 0));
 }
 
-const duk::FunctionMap methods{
-	{ "find",		{ methodFind,		DUK_VARARGS	} },
-	{ "remove",		{ methodRemove,		1		} }
+const duk_function_list_entry methods[] = {
+	{ "find",		methodFind,		DUK_VARARGS	},
+	{ "remove",		methodRemove,		1		},
+	{ nullptr,		nullptr,		0		} 
 };
 
-/* --------------------------------------------------------
+/*
  * Directory "static" functions
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 /*
  * Function: Irccd.Directory(path, flags) [constructor]
@@ -239,40 +242,42 @@
  * Throws:
  *   - Any exception on error
  */
-duk::Ret constructor(duk::Context *ctx)
+duk_ret_t constructor(duk_context *ctx)
 {
 	if (!duk_is_constructor_call(ctx))
 		return 0;
 
 	try {
-		std::string path = duk::require<std::string>(ctx, 0);
-		std::int8_t flags = duk::optional<int>(ctx, 1, 0);
+		std::string path = duk_require_string(ctx, 0);
+		std::int8_t flags = duk_get_uint(ctx, 1);
 
 		if (!fs::isDirectory(path))
-			duk::raise(ctx, SystemError(EINVAL, "not a directory"));
+			duk_throw(ctx, SystemError(EINVAL, "not a directory"));
 
 		std::vector<fs::Entry> list = fs::readdir(path, flags);
 
-		duk::push(ctx, duk::This{});
-		duk::push(ctx, "count");
-		duk::push(ctx, (int)list.size());
-		duk::defineProperty(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
-		duk::push(ctx, "path");
-		duk::push(ctx, path);
-		duk::defineProperty(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
-		duk::push(ctx, "entries");
-		duk::push(ctx, duk::Array{});
+		duk_push_this(ctx);
+		duk_push_string(ctx, "count");
+		duk_push_int(ctx, list.size());
+		duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
+		duk_push_string(ctx, "path");
+		duk_push_stdstring(ctx, path);
+		duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
+		duk_push_string(ctx, "entries");
+		duk_push_array(ctx);
 
 		for (unsigned i = 0; i < list.size(); ++i) {
-			duk::push(ctx, duk::Object{});
-			duk::putProperty(ctx, -1, "name", list[i].name);
-			duk::putProperty(ctx, -1, "type", static_cast<int>(list[i].type));
-			duk::putProperty(ctx, -2, (int)i);
+			duk_push_object(ctx);
+			duk_push_stdstring(ctx, list[i].name);
+			duk_put_prop_string(ctx, -2, "name");
+			duk_push_int(ctx, list[i].type);
+			duk_put_prop_string(ctx, -2, "type");
+			duk_put_prop_index(ctx, -2, i);
 		}
 
-		duk::defineProperty(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
+		duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
 	} catch (const std::exception &ex) {
-		duk::raise(ctx, SystemError(errno, ex.what()));
+		duk_throw(ctx, SystemError(errno, ex.what()));
 	}
 
 	return 0;
@@ -291,9 +296,9 @@
  * Returns:
  *   The path to the file or undefined on errors or not found.
  */
-duk::Ret funcFind(duk::Context *ctx)
+duk_ret_t funcFind(duk_context *ctx)
 {
-	return find(ctx, duk::require<std::string>(ctx, 0), duk::optional<bool>(ctx, 2, false), 1);
+	return find(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 2), 1);
 }
 
 /*
@@ -308,9 +313,9 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret funcRemove(duk::Context *ctx)
+duk_ret_t funcRemove(duk_context *ctx)
 {
-	return remove(ctx, duk::require<std::string>(ctx, 0), duk::optional<bool>(ctx, 1, false));
+	return remove(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 1));
 }
 
 /*
@@ -326,30 +331,35 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret funcMkdir(duk::Context *ctx)
+duk_ret_t funcMkdir(duk_context *ctx)
 {
 	try {
-		fs::mkdir(duk::require<std::string>(ctx, 0), duk::optional<int>(ctx, 1, 0700));
+		fs::mkdir(
+			duk_require_string(ctx, 0),
+			duk_is_number(ctx, 1) ? duk_get_int(ctx, 1) : 0700
+		);
 	} catch (const std::exception &ex) {
-		duk::raise(ctx, SystemError(errno, ex.what()));
+		duk_throw(ctx, SystemError(errno, ex.what()));
 	}
 
 	return 0;
 }
 
-const duk::FunctionMap functions{
-	{ "find",		{ funcFind,	DUK_VARARGS } },
-	{ "mkdir",		{ funcMkdir,	DUK_VARARGS } },
-	{ "remove",		{ funcRemove,	DUK_VARARGS } }
+const duk_function_list_entry functions[] = {
+	{ "find",		funcFind,	DUK_VARARGS	},
+	{ "mkdir",		funcMkdir,	DUK_VARARGS	},
+	{ "remove",		funcRemove,	DUK_VARARGS	},
+	{ nullptr,		nullptr,	0		} 
 };
 
-const duk::Map<int> constants{
+const duk_number_list_entry constants[] = {
 	{ "Dot",		static_cast<int>(fs::Dot)			},
 	{ "DotDot",		static_cast<int>(fs::DotDot)			},
 	{ "TypeUnknown",	static_cast<int>(fs::Entry::Unknown)		},
 	{ "TypeDir",		static_cast<int>(fs::Entry::Dir)		},
 	{ "TypeFile",		static_cast<int>(fs::Entry::File)		},
-	{ "TypeLink",		static_cast<int>(fs::Entry::Link)		}
+	{ "TypeLink",		static_cast<int>(fs::Entry::Link)		},
+	{ nullptr,		0						} 
 };
 
 } // !namespace
@@ -361,18 +371,19 @@
 
 void DirectoryModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function{constructor, 2});
-	duk::put(plugin.context(), constants);
-	duk::put(plugin.context(), functions);
-	duk::putProperty(plugin.context(), -1, "separator", std::string{fs::separator()});
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), methods);
-	duk::putProperty(plugin.context(), -2, "prototype");
-	duk::putProperty(plugin.context(), -2, "Directory");
-	duk::pop(plugin.context());
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_c_function(plugin.context(), constructor, 2);
+	duk_put_number_list(plugin.context(), -1, constants);
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_push_stdstring(plugin.context(), std::string{fs::separator()});
+	duk_put_prop_string(plugin.context(), -2, "separator");
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, methods);
+	duk_put_prop_string(plugin.context(), -2, "prototype");
+	duk_put_prop_string(plugin.context(), -2, "Directory");
+	duk_pop(plugin.context());
 }
 
 } // !irccd
--- a/lib/irccd/mod-elapsed-timer.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-elapsed-timer.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -24,38 +24,22 @@
 
 namespace {
 
-const std::string Signature{"\xff""\xff""irccd-elapsed-timer-ptr"};
-
-} // !namespace
-
-namespace duk {
+const char *Signature("\xff""\xff""irccd-elapsed-timer-ptr");
 
-template <>
-class TypeTraits<ElapsedTimer *> {
-public:
-	static inline void construct(duk::Context *ctx, ElapsedTimer *timer)
-	{
-		duk::StackAssert sa(ctx);
+ElapsedTimer *self(duk_context *ctx)
+{
+	StackAssert sa(ctx);
 
-		duk::push(ctx, duk::This());
-		duk::putProperty(ctx, -1, Signature, static_cast<void *>(timer));
-		duk::pop(ctx);
-	}
-
-	static inline ElapsedTimer *require(duk::Context *ctx, Index index)
-	{
-		auto ptr = static_cast<ElapsedTimer *>(duk::getProperty<void *>(ctx, index, Signature));
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, Signature);
+	auto ptr = static_cast<ElapsedTimer *>(duk_to_pointer(ctx, -1));
+	duk_pop_2(ctx);
 
-		if (!ptr)
-			duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object");
+	if (!ptr)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object");
 
-		return ptr;
-	}
-};
-
-} // !duk
-
-namespace {
+	return ptr;
+}
 
 /*
  * Method: ElapsedTimer.pause
@@ -63,9 +47,9 @@
  *
  * Pause the timer, without resetting the current elapsed time stored.
  */
-duk::Ret pause(duk::Context *ctx)
+duk_ret_t pause(duk_context *ctx)
 {
-	duk::self<ElapsedTimer *>(ctx)->pause();
+	self(ctx)->pause();
 
 	return 0;
 }
@@ -76,9 +60,9 @@
  *
  * Reset the elapsed time to 0, the status is not modified.
  */
-duk::Ret reset(duk::Context *ctx)
+duk_ret_t reset(duk_context *ctx)
 {
-	duk::self<ElapsedTimer *>(ctx)->reset();
+	self(ctx)->reset();
 
 	return 0;
 }
@@ -89,9 +73,9 @@
  *
  * Restart the timer without resetting the current elapsed time.
  */
-duk::Ret restart(duk::Context *ctx)
+duk_ret_t restart(duk_context *ctx)
 {
-	duk::self<ElapsedTimer *>(ctx)->restart();
+	self(ctx)->restart();
 
 	return 0;
 }
@@ -105,9 +89,9 @@
  * Returns:
  *   The time elapsed.
  */
-duk::Ret elapsed(duk::Context *ctx)
+duk_ret_t elapsed(duk_context *ctx)
 {
-	duk::push(ctx, static_cast<int>(duk::self<ElapsedTimer *>(ctx)->elapsed()));
+	duk_push_uint(ctx, self(ctx)->elapsed());
 
 	return 1;
 }
@@ -118,9 +102,12 @@
  *
  * Construct a new ElapsedTimer object.
  */
-duk::Ret constructor(duk::Context *ctx)
+duk_ret_t constructor(duk_context *ctx)
 {
-	duk::construct(ctx, new ElapsedTimer);
+	duk_push_this(ctx);
+	duk_push_pointer(ctx, new ElapsedTimer);
+	duk_put_prop_string(ctx, -2, Signature);
+	duk_pop_2(ctx);
 
 	return 0;
 }
@@ -131,20 +118,22 @@
  *
  * Delete the property.
  */
-duk::Ret destructor(duk::Context *ctx)
+duk_ret_t destructor(duk_context *ctx)
 {
-	delete static_cast<ElapsedTimer *>(duk::getProperty<void *>(ctx, 0, Signature));
-
-	duk::deleteProperty(ctx, 0, Signature);
+	duk_get_prop_string(ctx, 0, Signature);
+	delete static_cast<ElapsedTimer *>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+	duk_del_prop_string(ctx, 0, Signature);
 
 	return 0;
 }
 
-const duk::FunctionMap methods{
-	{ "elapsed",	{ elapsed,	0 } },
-	{ "pause",	{ pause,	0 } },
-	{ "reset",	{ reset,	0 } },
-	{ "restart",	{ restart,	0 } }
+const duk_function_list_entry methods[] = {
+	{ "elapsed",	elapsed,	0 },
+	{ "pause",	pause,		0 },
+	{ "reset",	reset,		0 },
+	{ "restart",	restart,	0 },
+	{ nullptr,	nullptr,	0 }
 };
 
 } // !namespace
@@ -156,17 +145,17 @@
 
 void ElapsedTimerModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function{constructor, 0});
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), methods);
-	duk::push(plugin.context(), duk::Function(destructor, 1));
-	duk::setFinalizer(plugin.context(), -2);
-	duk::putProperty(plugin.context(), -2, "prototype");
-	duk::putProperty(plugin.context(), -2, "ElapsedTimer");
-	duk::pop(plugin.context());
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_c_function(plugin.context(), constructor, 0);
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, methods);
+	duk_push_c_function(plugin.context(), destructor, 1);
+	duk_set_finalizer(plugin.context(), -2);
+	duk_put_prop_string(plugin.context(), -2, "prototype");
+	duk_put_prop_string(plugin.context(), -2, "ElapsedTimer");
+	duk_pop(plugin.context());
 }
 
 } // !irccd
--- a/lib/irccd/mod-file.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-file.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -38,80 +38,78 @@
 
 namespace {
 
-const std::string Signature("\xff""\xff""irccd-file-ptr");
-const std::string Prototype("\xff""\xff""irccd-file-prototype");
-
-} // !namespace
+const char *Signature("\xff""\xff""irccd-file-ptr");
+const char *Prototype("\xff""\xff""irccd-file-prototype");
 
 #if defined(HAVE_STAT)
 
 /*
- * duk::TypeInfo specialization for struct stat
+ * pushStat
  * ------------------------------------------------------------------
  */
 
-namespace duk {
+void pushStat(duk_context *ctx, const struct stat &st)
+{
+	StackAssert sa(ctx, 1);
 
-template <>
-class TypeTraits<struct stat> {
-public:
-	static void push(Context *ctx, const struct stat &st)
-	{
-		duk::push(ctx, Object{});
+	duk_push_object(ctx);
 
 #if defined(HAVE_STAT_ST_ATIME)
-		duk::putProperty(ctx, -2, "atime", static_cast<int>(st.st_atime));
+	duk_push_int(ctx, st.st_atime);
+	duk_put_prop_string(ctx, -2, "atime");
 #endif
 #if defined(HAVE_STAT_ST_BLKSIZE)
-		duk::putProperty(ctx, -2, "blksize", static_cast<int>(st.st_blksize));
+	duk_push_int(ctx, st.st_blksize);
+	duk_put_prop_string(ctx, -2, "blksize");
 #endif
 #if defined(HAVE_STAT_ST_BLOCKS)
-		duk::putProperty(ctx, -2, "blocks", static_cast<int>(st.st_blocks));
+	duk_push_int(ctx, st.st_blocks);
+	duk_put_prop_string(ctx, -2, "blocks");
 #endif
 #if defined(HAVE_STAT_ST_CTIME)
-		duk::putProperty(ctx, -2, "ctime", static_cast<int>(st.st_ctime));
+	duk_push_int(ctx, st.st_ctime);
+	duk_put_prop_string(ctx, -2, "ctime");
 #endif
 #if defined(HAVE_STAT_ST_DEV)
-		duk::putProperty(ctx, -2, "dev", static_cast<int>(st.st_dev));
+	duk_push_int(ctx, st.st_dev);
+	duk_put_prop_string(ctx, -2, "dev");
 #endif
 #if defined(HAVE_STAT_ST_GID)
-		duk::putProperty(ctx, -2, "gid", static_cast<int>(st.st_gid));
+	duk_push_int(ctx, st.st_gid);
+	duk_put_prop_string(ctx, -2, "gid");
 #endif
 #if defined(HAVE_STAT_ST_INO)
-		duk::putProperty(ctx, -2, "ino", static_cast<int>(st.st_ino));
+	duk_push_int(ctx, st.st_ino);
+	duk_put_prop_string(ctx, -2, "ino");
 #endif
 #if defined(HAVE_STAT_ST_MODE)
-		duk::putProperty(ctx, -2, "mode", static_cast<int>(st.st_mode));
+	duk_push_int(ctx, st.st_mode);
+	duk_put_prop_string(ctx, -2, "mode");
 #endif
 #if defined(HAVE_STAT_ST_MTIME)
-		duk::putProperty(ctx, -2, "mtime", static_cast<int>(st.st_mtime));
+	duk_push_int(ctx, st.st_mtime);
+	duk_put_prop_string(ctx, -2, "mtime");
 #endif
 #if defined(HAVE_STAT_ST_NLINK)
-		duk::putProperty(ctx, -2, "nlink", static_cast<int>(st.st_nlink));
+	duk_push_int(ctx, st.st_nlink);
+	duk_put_prop_string(ctx, -2, "nlink");
 #endif
 #if defined(HAVE_STAT_ST_RDEV)
-		duk::putProperty(ctx, -2, "rdev", static_cast<int>(st.st_rdev));
+	duk_push_int(ctx, st.st_rdev);
+	duk_put_prop_string(ctx, -2, "rdev");
 #endif
 #if defined(HAVE_STAT_ST_SIZE)
-		duk::putProperty(ctx, -2, "size", static_cast<int>(st.st_size));
+	duk_push_int(ctx, st.st_size);
+	duk_put_prop_string(ctx, -2, "size");
 #endif
 #if defined(HAVE_STAT_ST_UID)
-		duk::putProperty(ctx, -2, "uid", static_cast<int>(st.st_uid));
+	duk_push_int(ctx, st.st_uid);
+	duk_put_prop_string(ctx, -2, "uid");
 #endif
-	}
-};
-
-} // !duk
+}
 
 #endif // !HAVE_STAT
 
-namespace {
-
-/*
- * Anonymous helpers.
- * ------------------------------------------------------------------
- */
-
 // Remove trailing \r for CRLF line style.
 inline std::string clearCr(std::string input)
 {
@@ -121,6 +119,18 @@
 	return input;
 }
 
+inline File *self(duk_context *ctx)
+{
+	StackAssert sa(ctx);
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, Signature);
+	File *file = static_cast<File *>(duk_to_pointer(ctx, -1));
+	duk_pop_2(ctx);
+
+	return file;
+}
+
 /*
  * File methods.
  * ------------------------------------------------------------------
@@ -132,12 +142,12 @@
  *
  * Synonym of `Irccd.File.basename(path)` but with the path from the file.
  *
- * Returns:
+ * duk_ret_turns:
  *   The base name.
  */
-duk::Ret methodBasename(duk::Context *ctx)
+duk_ret_t methodBasename(duk_context *ctx)
 {
-	duk::push(ctx, fs::baseName(duk::self<File *>(ctx)->path()));
+	duk_push_stdstring(ctx, fs::baseName(self(ctx)->path()));
 
 	return 1;
 }
@@ -148,9 +158,9 @@
  *
  * Force close of the file, automatically called when object is collected.
  */
-duk::Ret methodClose(duk::Context *ctx)
+duk_ret_t methodClose(duk_context *ctx)
 {
-	duk::self<File *>(ctx)->close();
+	self(ctx)->close();
 
 	return 0;
 }
@@ -161,12 +171,12 @@
  *
  * Synonym of `Irccd.File.dirname(path)` but with the path from the file.
  *
- * Returns:
+ * duk_ret_turns:
  *   The directory name.
  */
-duk::Ret methodDirname(duk::Context *ctx)
+duk_ret_t methodDirname(duk_context *ctx)
 {
-	duk::push(ctx, fs::dirName(duk::self<File *>(ctx)->path()));
+	duk_push_stdstring(ctx, fs::dirName(self(ctx)->path()));
 
 	return 1;
 }
@@ -177,16 +187,16 @@
  *
  * Read all lines and return an array.
  *
- * Returns:
+ * duk_ret_turns:
  *   An array with all lines.
  * Throws
  *   - Any exception on error.
  */
-duk::Ret methodLines(duk::Context *ctx)
+duk_ret_t methodLines(duk_context *ctx)
 {
-	duk::push(ctx, duk::Array{});
+	duk_push_array(ctx);
 
-	std::FILE *fp = duk::self<File *>(ctx)->handle();
+	std::FILE *fp = self(ctx)->handle();
 	std::string buffer;
 	std::array<char, 128> data;
 	std::int32_t i = 0;
@@ -197,18 +207,22 @@
 		auto pos = buffer.find('\n');
 
 		if (pos != std::string::npos) {
-			duk::putProperty(ctx, -1, i++, clearCr(buffer.substr(0, pos)));
+			duk_push_stdstring(ctx, clearCr(buffer.substr(0, pos)));
+			duk_put_prop_index(ctx, -2, i++);
+
 			buffer.erase(0, pos + 1);
 		}
 	}
 
 	// Maybe an error in the stream.
 	if (std::ferror(fp))
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 
 	// Missing '\n' in end of file.
-	if (!buffer.empty())
-		duk::putProperty(ctx, -1, i++, clearCr(buffer));
+	if (!buffer.empty()) {
+		duk_push_stdstring(ctx, clearCr(buffer));
+		duk_put_prop_index(ctx, -2, i++);
+	}
 
 	return 1;
 }
@@ -221,15 +235,15 @@
  *
  * Arguments:
  *   - amount, the amount of characters or -1 to read all (Optional, default: -1).
- * Returns:
+ * duk_ret_turns:
  *   The string.
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodRead(duk::Context *ctx)
+duk_ret_t methodRead(duk_context *ctx)
 {
-	auto amount = duk::optional<int>(ctx, 0, -1);
-	auto file = duk::self<File *>(ctx);
+	auto file = self(ctx);
+	auto amount = duk_is_number(ctx, 0) ? duk_get_int(ctx, 0) : 0;
 
 	if (amount == 0 || file->handle() == nullptr)
 		return 0;
@@ -246,7 +260,7 @@
 				nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle());
 
 				if (std::ferror(file->handle()))
-					duk::raise(ctx, SystemError());
+					duk_throw(ctx, SystemError());
 
 				std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data));
 				total += nread;
@@ -256,14 +270,14 @@
 			total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle());
 
 			if (std::ferror(file->handle()))
-				duk::raise(ctx, SystemError());
+				duk_throw(ctx, SystemError());
 
 			data.resize(total);
 		}
 
-		duk::push(ctx, data);
+		duk_push_stdstring(ctx, data);
 	} catch (const std::exception &) {
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 	}
 
 	return 1;
@@ -275,14 +289,14 @@
  *
  * Read the next line available.
  *
- * Returns:
+ * duk_ret_turns:
  *   The next line or undefined if eof.
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodReadline(duk::Context *ctx)
+duk_ret_t methodReadline(duk_context *ctx)
 {
-	std::FILE *fp = duk::self<File *>(ctx)->handle();
+	std::FILE *fp = self(ctx)->handle();
 	std::string result;
 
 	if (fp == nullptr || std::feof(fp))
@@ -290,9 +304,9 @@
 	for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; )
 		result += (char)ch;
 	if (std::ferror(fp))
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 
-	duk::push(ctx, clearCr(result));
+	duk_push_stdstring(ctx, clearCr(result));
 
 	return 1;
 }
@@ -306,10 +320,10 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodRemove(duk::Context *ctx)
+duk_ret_t methodRemove(duk_context *ctx)
 {
-	if (::remove(duk::self<File *>(ctx)->path().c_str()) < 0)
-		duk::raise(ctx, SystemError());
+	if (::remove(self(ctx)->path().c_str()) < 0)
+		duk_throw(ctx, SystemError());
 
 	return 0;
 }
@@ -326,14 +340,14 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodSeek(duk::Context *ctx)
+duk_ret_t methodSeek(duk_context *ctx)
 {
-	auto type = duk::require<int>(ctx, 0);
-	auto amount = duk::require<int>(ctx, 1);
-	auto fp = duk::self<File *>(ctx)->handle();
+	auto fp = self(ctx)->handle();
+	auto type = duk_require_int(ctx, 0);
+	auto amount = duk_require_int(ctx, 1);
 
 	if (fp != nullptr && std::fseek(fp, amount, type) != 0)
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 
 	return 0;
 }
@@ -346,20 +360,20 @@
  *
  * Synonym of File.stat(path) but with the path from the file.
  *
- * Returns:
+ * duk_ret_turns:
  *   The stat information.
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodStat(duk::Context *ctx)
+duk_ret_t methodStat(duk_context *ctx)
 {
+	auto file = self(ctx);
 	struct stat st;
-	auto file = duk::self<File *>(ctx);
 
 	if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0)
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 	else
-		duk::push(ctx, st);
+		pushStat(ctx, st);
 
 	return 1;
 }
@@ -372,23 +386,23 @@
  *
  * Get the actual position in the file.
  *
- * Returns:
+ * duk_ret_turns:
  *   The position.
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodTell(duk::Context *ctx)
+duk_ret_t methodTell(duk_context *ctx)
 {
-	auto fp = duk::self<File *>(ctx)->handle();
+	auto fp = self(ctx)->handle();
 	long pos;
 
 	if (fp == nullptr)
 		return 0;
 
 	if ((pos = std::ftell(fp)) == -1L)
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 	else
-		duk::push(ctx, (int)pos);
+		duk_push_int(ctx, pos);
 
 	return 1;
 }
@@ -401,15 +415,15 @@
  *
  * Arguments:
  *   - data, the character to write.
- * Returns:
+ * duk_ret_turns:
  *   The number of bytes written.
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodWrite(duk::Context *ctx)
+duk_ret_t methodWrite(duk_context *ctx)
 {
-	std::FILE *fp = duk::self<File *>(ctx)->handle();
-	std::string data = duk::require<std::string>(ctx, 0);
+	std::FILE *fp = self(ctx)->handle();
+	std::string data = duk_require_string(ctx, 0);
 
 	if (fp == nullptr)
 		return 0;
@@ -417,27 +431,28 @@
 	std::size_t nwritten = std::fwrite(data.c_str(), 1, data.length(), fp);
 
 	if (std::ferror(fp))
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 
-	duk::push(ctx, (int)nwritten);
+	duk_push_uint(ctx, nwritten);
 
 	return 1;
 }
 
-const duk::FunctionMap methods{
-	{ "basename",	{ methodBasename,	0	} },
-	{ "close",	{ methodClose,		0	} },
-	{ "dirname",	{ methodDirname,	0	} },
-	{ "lines",	{ methodLines,		0	} },
-	{ "read",	{ methodRead,		1	} },
-	{ "readline",	{ methodReadline,	0	} },
-	{ "remove",	{ methodRemove,		0	} },
-	{ "seek",	{ methodSeek,		2	} },
+const duk_function_list_entry methods[] = {
+	{ "basename",	methodBasename,		0	},
+	{ "close",	methodClose,		0	},
+	{ "dirname",	methodDirname,		0	},
+	{ "lines",	methodLines,		0	},
+	{ "read",	methodRead,		1	},
+	{ "readline",	methodReadline,		0	},
+	{ "remove",	methodRemove,		0	},
+	{ "seek",	methodSeek,		2	},
 #if defined(HAVE_STAT)
-	{ "stat",	{ methodStat,		0	} },
+	{ "stat",	methodStat,		0	},
 #endif
-	{ "tell",	{ methodTell,		0	} },
-	{ "write",	{ methodWrite,		1	} },
+	{ "tell",	methodTell,		0	},
+	{ "write",	methodWrite,		1	},
+	{ nullptr,	nullptr,		0	}
 };
 
 /*
@@ -457,15 +472,15 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret constructor(duk::Context *ctx)
+duk_ret_t constructor(duk_context *ctx)
 {
-	if (!duk::isConstructorCall(ctx))
+	if (!duk_is_constructor_call(ctx))
 		return 0;
 
 	try {
-		duk::construct(ctx, new File(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)));
+		duk_new_file(ctx, new File(duk_require_string(ctx, 0), duk_require_string(ctx, 1)));
 	} catch (const std::exception &) {
-		duk::raise(ctx, SystemError());
+		duk_throw(ctx, SystemError());
 	}
 
 	return 0;
@@ -477,11 +492,12 @@
  *
  * Delete the property.
  */
-duk::Ret destructor(duk::Context *ctx)
+duk_ret_t destructor(duk_context *ctx)
 {
-	delete static_cast<File *>(duk::getProperty<void *>(ctx, 0, Signature));
-
-	duk::deleteProperty(ctx, 0, Signature);
+	duk_get_prop_string(ctx, 0, Signature);
+	delete static_cast<File *>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+	duk_del_prop_string(ctx, 0, Signature);
 
 	return 0;
 }
@@ -490,16 +506,16 @@
  * Function: Irccd.File.basename(path)
  * --------------------------------------------------------
  *
- * Return the file basename as specified in `basename(3)` C function.
+ * duk_ret_turn the file basename as specified in `basename(3)` C function.
  *
  * Arguments:
  *   - path, the path to the file.
- * Returns:
+ * duk_ret_turns:
  *   The base name.
  */
-duk::Ret functionBasename(duk::Context *ctx)
+duk_ret_t functionBasename(duk_context *ctx)
 {
-	duk::push(ctx, fs::baseName(duk::require<std::string>(ctx, 0)));
+	duk_push_stdstring(ctx, fs::baseName(duk_require_string(ctx, 0)));
 
 	return 1;
 }
@@ -508,16 +524,16 @@
  * Function: Irccd.File.dirname(path)
  * --------------------------------------------------------
  *
- * Return the file directory name as specified in `dirname(3)` C function.
+ * duk_ret_turn the file directory name as specified in `dirname(3)` C function.
  *
  * Arguments:
  *   - path, the path to the file.
- * Returns:
+ * duk_ret_turns:
  *   The directory name.
  */
-duk::Ret functionDirname(duk::Context *ctx)
+duk_ret_t functionDirname(duk_context *ctx)
 {
-	duk::push(ctx, fs::dirName( duk::require<std::string>(ctx, 0)));
+	duk_push_stdstring(ctx, fs::dirName(duk_require_string(ctx, 0)));
 
 	return 1;
 }
@@ -530,14 +546,14 @@
  *
  * Arguments:
  *   - path, the path to the file.
- * Returns:
+ * duk_ret_turns:
  *   True if exists.
  * Throws:
  *   - Any exception if we don't have access.
  */
-duk::Ret functionExists(duk::Context *ctx)
+duk_ret_t functionExists(duk_context *ctx)
 {
-	duk::push(ctx, fs::exists(duk::require<std::string>(ctx, 0)));
+	duk_push_boolean(ctx, fs::exists(duk_require_string(ctx, 0)));
 
 	return 1;
 }
@@ -553,10 +569,10 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret functionRemove(duk::Context *ctx)
+duk_ret_t functionRemove(duk_context *ctx)
 {
-	if (::remove(duk::require<std::string>(ctx, 0).c_str()) < 0)
-		duk::raise(ctx, SystemError());
+	if (::remove(duk_require_string(ctx, 0)) < 0)
+		duk_throw(ctx, SystemError());
 
 	return 0;
 }
@@ -571,36 +587,37 @@
  *
  * Arguments:
  *   - path, the path to the file.
- * Returns:
+ * duk_ret_turns:
  *   The stat information.
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret functionStat(duk::Context *ctx)
+duk_ret_t functionStat(duk_context *ctx)
 {
 	struct stat st;
 
-	if (::stat(duk::require<std::string>(ctx, 0).c_str(), &st) < 0)
-		duk::raise(ctx, SystemError());
+	if (::stat(duk_require_string(ctx, 0), &st) < 0)
+		duk_throw(ctx, SystemError());
 
-	duk::push(ctx, st);
+	pushStat(ctx, st);
 
 	return 1;
 }
 
 #endif // !HAVE_STAT
 
-const duk::FunctionMap functions{
-	{ "basename",	{ functionBasename,	1			} },
-	{ "dirname",	{ functionDirname,	1			} },
-	{ "exists",	{ functionExists,	1			} },
-	{ "remove",	{ functionRemove,	1			} },
+const duk_function_list_entry functions[] = {
+	{ "basename",	functionBasename,	1 },
+	{ "dirname",	functionDirname,	1 },
+	{ "exists",	functionExists,		1 },
+	{ "remove",	functionRemove,		1 },
 #if defined(HAVE_STAT)
-	{ "stat",	{ functionStat,		1			} },
+	{ "stat",	functionStat,		1 },
 #endif
+	{ nullptr,	nullptr,		0 } 
 };
 
-const duk::Map<int> constants{
+const duk_number_list_entry constants[] = {
 	{ "SeekCur",	SEEK_CUR },
 	{ "SeekEnd",	SEEK_END },
 	{ "SeekSet",	SEEK_SET },
@@ -608,41 +625,6 @@
 
 } // !namespace
 
-namespace duk {
-
-void TypeTraits<File *>::construct(duk::Context *ctx, File *fp)
-{
-	assert(fp);
-
-	duk::StackAssert sa(ctx);
-
-	duk::push(ctx, duk::This());
-	duk::putProperty(ctx, -1, Signature, static_cast<void *>(fp));
-	duk::pop(ctx);
-}
-
-void TypeTraits<File *>::push(duk::Context *ctx, File *fp)
-{
-	duk::StackAssert sa(ctx, 1);
-
-	duk::push(ctx, duk::Object());
-	duk::putProperty(ctx, -1, Signature, static_cast<void *>(fp));
-	duk::getGlobal<void>(ctx, Prototype);
-	duk::setPrototype(ctx, -2);
-}
-
-File *TypeTraits<File *>::require(duk::Context *ctx, Index index)
-{
-	auto ptr = static_cast<File *>(duk::getProperty<void *>(ctx, index, Signature));
-
-	if (!ptr)
-		duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
-
-	return ptr;
-}
-
-} // !duk
-
 FileModule::FileModule() noexcept
 	: Module("Irccd.File")
 {
@@ -650,21 +632,60 @@
 
 void FileModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
+
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_c_function(plugin.context(), constructor, 2);
+	duk_put_number_list(plugin.context(), -1, constants);
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, methods);
+	duk_push_c_function(plugin.context(), destructor, 1);
+	duk_set_finalizer(plugin.context(), -2);
+	duk_dup(plugin.context(), -1);
+	duk_get_global_string(plugin.context(), Prototype);
+	duk_put_prop_string(plugin.context(), -2, "prototype");
+	duk_put_prop_string(plugin.context(), -2, "File");
+	duk_pop(plugin.context());
+}
+
+void duk_new_file(duk_context *ctx, File *fp)
+{
+	assert(ctx);
+	assert(fp);
+
+	StackAssert sa(ctx);
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function(constructor, 2));
-	duk::put(plugin.context(), constants);
-	duk::put(plugin.context(), functions);
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), methods);
-	duk::push(plugin.context(), duk::Function(destructor, 1));
-	duk::setFinalizer(plugin.context(), -2);
-	duk::dup(plugin.context(), -1);
-	duk::putGlobal(plugin.context(), Prototype);
-	duk::putProperty(plugin.context(), -2, "prototype");
-	duk::putProperty(plugin.context(), -2, "File");
-	duk::pop(plugin.context());
+	duk_push_this(ctx);
+	duk_push_pointer(ctx, fp);
+	duk_put_prop_string(ctx, -2, Signature);
+	duk_pop(ctx);
+}
+
+void duk_push_file(duk_context *ctx, File *fp)
+{
+	assert(ctx);
+	assert(fp);
+
+	StackAssert sa(ctx, 1);
+
+	duk_push_object(ctx);
+	duk_push_pointer(ctx, fp);
+	duk_put_prop_string(ctx, -2, Signature);
+	duk_get_global_string(ctx, Prototype);
+	duk_set_prototype(ctx, -2);
+}
+
+File *duk_require_file(duk_context *ctx, duk_idx_t index)
+{
+	if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature))
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
+
+	duk_get_prop_string(ctx, index, Signature);
+	File *file = static_cast<File *>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+
+	return file;
 }
 
 } // !irccd
--- a/lib/irccd/mod-file.hpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-file.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -32,7 +32,7 @@
 #include <stdexcept>
 #include <string>
 
-#include "js.hpp"
+#include "duktape.hpp"
 #include "module.hpp"
 
 namespace irccd {
@@ -136,43 +136,6 @@
 	}
 };
 
-namespace duk {
-
-/**
- * \brief JavaScript binding for File.
- */
-template <>
-class TypeTraits<File *> {
-public:
-	/**
-	 * Construct the file.
-	 *
-	 * \pre fp != nullptr
-	 * \param ctx the the context
-	 * \param fp the file
-	 */
-	IRCCD_EXPORT static void construct(duk::Context *ctx, File *fp);
-
-	/**
-	 * Push a file.
-	 *
-	 * \pre fp != nullptr
-	 * \param ctx the the context
-	 * \param fp the file
-	 */
-	IRCCD_EXPORT static void push(duk::Context *ctx, File *fp);
-
-	/**
-	 * Require a file. Raises a JavaScript error if not a File.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 */
-	IRCCD_EXPORT static File *require(duk::Context *ctx, Index index);
-};
-
-} // !duk
-
 /**
  * \brief Irccd.File JavaScript API.
  * \ingroup modules
@@ -190,6 +153,34 @@
 	IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override;
 };
 
+/**
+ * Construct the file as this.
+ *
+ * The object prototype takes ownership of fp and will be deleted once collected.
+ *
+ * \pre fp != nullptr
+ * \param ctx the the context
+ * \param fp the file
+ */
+IRCCD_EXPORT void duk_new_file(duk_context *ctx, File *fp);
+
+/**
+ * Push a file.
+ *
+ * \pre fp != nullptr
+ * \param ctx the the context
+ * \param fp the file
+ */
+IRCCD_EXPORT void duk_push_file(duk_context *ctx, File *fp);
+
+/**
+ * Require a file. Raises a JavaScript error if not a File.
+ *
+ * \param ctx the context
+ * \param index the index
+ */
+IRCCD_EXPORT File *duk_require_file(duk_context *ctx, duk_idx_t index);
+
 } // !irccd
 
 #endif // !IRCCD_MOD_FILE_HPP
--- a/lib/irccd/mod-irccd.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-irccd.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -22,6 +22,24 @@
 
 namespace irccd {
 
+namespace {
+
+duk_ret_t constructor(duk_context *ctx)
+{
+	duk_push_this(ctx);
+	duk_push_int(ctx, duk_require_int(ctx, 0));
+	duk_put_prop_string(ctx, -2, "errno");
+	duk_push_string(ctx, duk_require_string(ctx, 1));
+	duk_put_prop_string(ctx, -2, "message");
+	duk_push_string(ctx, "SystemError");
+	duk_put_prop_string(ctx, -2, "name");
+	duk_pop(ctx);
+
+	return 0;
+}
+
+} // !namespace
+
 SystemError::SystemError()
 	: m_errno(errno)
 	, m_message(std::strerror(m_errno))
@@ -34,28 +52,17 @@
 {
 }
 
-void SystemError::raise(duk::Context *ctx) const
+void SystemError::raise(duk_context *ctx) const
 {
-	duk::StackAssert sa(ctx, 0);
+	StackAssert sa(ctx, 0);
 
-	duk::getGlobal<void>(ctx, "Irccd");
-	duk::getProperty<void>(ctx, -1, "SystemError");
-	duk::remove(ctx, -2);
-	duk::push(ctx, m_errno);
-	duk::push(ctx, m_message);
-	duk::create(ctx, 2);
-	duk::raise(ctx);
-}
-
-duk::Ret constructor(duk::Context *ctx)
-{
-	duk::push(ctx, duk::This{});
-	duk::putProperty(ctx, -1, "errno", duk::require<int>(ctx, 0));
-	duk::putProperty(ctx, -1, "message", duk::require<std::string>(ctx, 1));
-	duk::putProperty(ctx, -1, "name", "SystemError");
-	duk::pop(ctx);
-
-	return 0;
+	duk_get_global_string(ctx, "Irccd");
+	duk_get_prop_string(ctx, -1, "SystemError");
+	duk_remove(ctx, -2);
+	duk_push_int(ctx, m_errno);
+	duk_push_stdstring(ctx, m_message);
+	duk_new(ctx, 2);
+	duk_throw(ctx);
 }
 
 IrccdModule::IrccdModule() noexcept
@@ -65,33 +72,48 @@
 
 void IrccdModule::load(Irccd &irccd, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
 	// Irccd.
-	duk::push(plugin.context(), duk::Object{});
+	duk_push_object(plugin.context());
 
 	// Version.
-	duk::push(plugin.context(), duk::Object{});
-	duk::putProperty(plugin.context(), -1, "major", IRCCD_VERSION_MAJOR);
-	duk::putProperty(plugin.context(), -1, "minor", IRCCD_VERSION_MINOR);
-	duk::putProperty(plugin.context(), -1, "patch", IRCCD_VERSION_PATCH);
-	duk::putProperty(plugin.context(), -2, "version");
+	duk_push_object(plugin.context());
+	duk_push_int(plugin.context(), IRCCD_VERSION_MAJOR);
+	duk_put_prop_string(plugin.context(), -2, "major");
+	duk_push_int(plugin.context(), IRCCD_VERSION_MINOR);
+	duk_put_prop_string(plugin.context(), -2, "minor");
+	duk_push_int(plugin.context(), IRCCD_VERSION_PATCH);
+	duk_put_prop_string(plugin.context(), -2, "patch");
+	duk_put_prop_string(plugin.context(), -2, "version");
 
 	// Create the SystemError that inherits from Error.
-	duk::push(plugin.context(), duk::Function{constructor, 2});
-	duk::push(plugin.context(), duk::Object{});
-	duk::getGlobal<void>(plugin.context(), "Error");
-	duk::getProperty<void>(plugin.context(), -1, "prototype");
-	duk::remove(plugin.context(), -2);
-	duk::setPrototype(plugin.context(), -2);
-	duk::putProperty(plugin.context(), -2, "prototype");
-	duk::putProperty(plugin.context(), -2, "SystemError");
+	duk_push_c_function(plugin.context(), constructor, 2);
+	duk_push_object(plugin.context());
+	duk_get_global_string(plugin.context(), "Error");
+	duk_put_prop_string(plugin.context(), -1, "prototype");
+	duk_remove(plugin.context(), -2);
+	duk_set_prototype(plugin.context(), -2);
+	duk_put_prop_string(plugin.context(), -2, "prototype");
+	duk_put_prop_string(plugin.context(), -2, "SystemError");
 
 	// Set Irccd as global.
-	duk::putGlobal(plugin.context(), "Irccd");
+	duk_put_global_string(plugin.context(), "Irccd");
 
 	// Store global instance.
-	duk::putGlobal(plugin.context(), "\xff""\xff""irccd",&irccd);
+	duk_push_pointer(plugin.context(), &irccd);
+	duk_put_global_string(plugin.context(), "\xff""\xff""irccd-ref");
+}
+
+Irccd &duk_get_irccd(duk_context *ctx)
+{
+	StackAssert sa(ctx);
+
+	duk_get_global_string(ctx, "\xff""\xff""irccd-ref");
+	Irccd *irccd = static_cast<Irccd *>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+
+	return *irccd;
 }
 
 } // !irccd
--- a/lib/irccd/mod-irccd.hpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-irccd.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -28,7 +28,7 @@
 #include <cstring>
 #include <string>
 
-#include "js.hpp"
+#include "duktape.hpp"
 #include "module.hpp"
 
 namespace irccd {
@@ -62,7 +62,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	IRCCD_EXPORT void raise(duk::Context *ctx) const;
+	IRCCD_EXPORT void raise(duk_context *ctx) const;
 };
 
 /**
@@ -82,6 +82,14 @@
 	IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override;
 };
 
+/**
+ * Get irccd instance stored in this context.
+ *
+ * \param ctx the context
+ * \return the irccd reference
+ */
+Irccd &duk_get_irccd(duk_context *ctx);
+
 } // !irccd
 
 #endif // !IRCCD_MOD_IRCCD_HPP
--- a/lib/irccd/mod-logger.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-logger.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -17,6 +17,7 @@
  */
 
 #include "mod-logger.hpp"
+#include "mod-plugin.hpp"
 #include "logger.hpp"
 #include "plugin-js.hpp"
 
@@ -24,14 +25,9 @@
 
 namespace {
 
-duk::Ret print(duk::Context *ctx, std::ostream &out)
+duk_ret_t print(duk_context *ctx, std::ostream &out)
 {
-	/*
-	 * Get the message before we start printing stuff to avoid
-	 * empty lines.
-	 */
-	out << "plugin " << duk::getGlobal<std::string>(ctx, "\xff""\xff""name");
-	out << ": " << duk::require<std::string>(ctx, 0) << std::endl;
+	out << "plugin " << duk_get_plugin(ctx)->name() << ": " << duk_require_string(ctx, 0) << std::endl;
 
 	return 0;
 }
@@ -45,7 +41,7 @@
  * Arguments:
  *   - message, the message.
  */
-duk::Ret info(duk::Context *ctx)
+duk_ret_t info(duk_context *ctx)
 {
 	return print(ctx, log::info());
 }
@@ -59,7 +55,7 @@
  * Arguments:
  *   - message, the warning.
  */
-duk::Ret warning(duk::Context *ctx)
+duk_ret_t warning(duk_context *ctx)
 {
 	return print(ctx, log::warning());
 }
@@ -73,15 +69,16 @@
  * Arguments:
  *   - message, the message.
  */
-duk::Ret debug(duk::Context *ctx)
+duk_ret_t debug(duk_context *ctx)
 {
 	return print(ctx, log::debug());
 }
 
-const duk::FunctionMap functions{
-	{ "info",	{ info,		1 } },
-	{ "warning",	{ warning,	1 } },
-	{ "debug",	{ debug,	1 } }
+const duk_function_list_entry functions[] = {
+	{ "info",	info,		1 },
+	{ "warning",	warning,	1 },
+	{ "debug",	debug,		1 },
+	{ nullptr,	nullptr,	0 }
 };
 
 } // !namespace
@@ -93,13 +90,13 @@
 
 void LoggerModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), functions);
-	duk::putProperty(plugin.context(), -2, "Logger");
-	duk::pop(plugin.context());
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_put_prop_string(plugin.context(), -2, "Logger");
+	duk_pop(plugin.context());
 }
 
 } // !irccd
--- a/lib/irccd/mod-plugin.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-plugin.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -19,13 +19,14 @@
 #include "irccd.hpp"
 #include "plugin-js.hpp"
 #include "service-plugin.hpp"
+#include "mod-irccd.hpp"
 #include "mod-plugin.hpp"
 
 namespace irccd {
 
 namespace {
 
-const std::string PluginGlobal{"\xff""\xff""irccd-plugin-ptr"};
+const char *PluginGlobal("\xff""\xff""irccd-plugin-ptr");
 
 /*
  * Wrap function for these functions because they all takes the same arguments.
@@ -35,16 +36,16 @@
  * - unload.
  */
 template <typename Func>
-duk::Ret wrap(duk::Context *ctx, int nret, Func &&func)
+duk_idx_t wrap(duk_context *ctx, int nret, Func &&func)
 {
-	std::string name = duk::require<std::string>(ctx, 0);
+	std::string name = duk_require_string(ctx, 0);
 
 	try {
-		func(*duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd"), name);
+		func(duk_get_irccd(ctx), name);
 	} catch (const std::out_of_range &ex) {
-		duk::raise(ctx, duk::ReferenceError(ex.what()));
+		duk_throw(ctx, ReferenceError(ex.what()));
 	} catch (const std::exception &ex) {
-		duk::raise(ctx, duk::Error(ex.what()));
+		duk_throw(ctx, Error(ex.what()));
 	}
 
 	return nret;
@@ -66,27 +67,32 @@
  *
  * Arguments:
  *   - name, the plugin identifier, if not specified the current plugin is selected.
- * Returns:
+ * duk_idx_turns:
  *   The plugin information or undefined if the plugin was not found.
  */
-duk::Ret info(duk::Context *ctx)
+duk_idx_t info(duk_context *ctx)
 {
-	Plugin *plugin = nullptr;
+	std::shared_ptr<Plugin> plugin;
 
-	if (duk::top(ctx) >= 1)
-		plugin = duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->pluginService().get(duk::require<std::string>(ctx, 0)).get();
+	if (duk_get_top(ctx) >= 1)
+		plugin = duk_get_irccd(ctx).pluginService().get(duk_require_string(ctx, 0));
 	else
-		plugin = duk::getGlobal<Plugin *>(ctx, "\xff""\xff""plugin");
+		plugin = duk_get_plugin(ctx);
 
 	if (!plugin)
 		return 0;
 
-	duk::push(ctx, duk::Object{});
-	duk::putProperty(ctx, -1, "name", plugin->name());
-	duk::putProperty(ctx, -1, "author", plugin->author());
-	duk::putProperty(ctx, -1, "license", plugin->license());
-	duk::putProperty(ctx, -1, "summary", plugin->summary());
-	duk::putProperty(ctx, -1, "version", plugin->version());
+	duk_push_object(ctx);
+	duk_push_stdstring(ctx, plugin->name());
+	duk_put_prop_string(ctx, -2, "name");
+	duk_push_stdstring(ctx, plugin->author());
+	duk_put_prop_string(ctx, -2, "author");
+	duk_push_stdstring(ctx, plugin->license());
+	duk_put_prop_string(ctx, -2, "license");
+	duk_push_stdstring(ctx, plugin->summary());
+	duk_put_prop_string(ctx, -2, "summary");
+	duk_push_stdstring(ctx, plugin->version());
+	duk_put_prop_string(ctx, -2, "version");
 
 	return 1;
 }
@@ -97,16 +103,18 @@
  *
  * Get the list of plugins, the array returned contains all plugin names.
  *
- * Returns:
+ * duk_idx_turns:
  *   The list of all plugin names.
  */
-duk::Ret list(duk::Context *ctx)
+duk_idx_t list(duk_context *ctx)
 {
-	duk::push(ctx, duk::Array{});
+	duk_push_array(ctx);
 
 	int i = 0;
-	for (const auto &plugin : duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->pluginService().plugins())
-		duk::putProperty(ctx, -1, i++, plugin->name());
+	for (const auto &plugin : duk_get_irccd(ctx).pluginService().plugins()) {
+		duk_push_stdstring(ctx, plugin->name());
+		duk_put_prop_index(ctx, -1, i++);
+	}
 
 	return 1;
 }
@@ -123,7 +131,7 @@
  *   - Error on errors,
  *   - ReferenceError if the plugin was not found.
  */
-duk::Ret load(duk::Context *ctx)
+duk_idx_t load(duk_context *ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
 		irccd.pluginService().load(name);
@@ -142,7 +150,7 @@
  *   - Error on errors,
  *   - ReferenceError if the plugin was not found.
  */
-duk::Ret reload(duk::Context *ctx)
+duk_idx_t reload(duk_context *ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
 		irccd.pluginService().reload(name);
@@ -161,32 +169,24 @@
  *   - Error on errors,
  *   - ReferenceError if the plugin was not found.
  */
-duk::Ret unload(duk::Context *ctx)
+duk_idx_t unload(duk_context *ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
 		irccd.pluginService().unload(name);
 	});
 }
 
-const duk::FunctionMap functions{
-	{ "info",	{ info,		DUK_VARARGS	} },
-	{ "list",	{ list,		0		} },
-	{ "load",	{ load,		1		} },
-	{ "reload",	{ reload,	1		} },
-	{ "unload",	{ unload,	1		} }
+const duk_function_list_entry functions[] = {
+	{ "info",	info,		DUK_VARARGS	},
+	{ "list",	list,		0		},
+	{ "load",	load,		1		},
+	{ "reload",	reload,		1		},
+	{ "unload",	unload,		1		},
+	{ nullptr,	nullptr,	0		}
 };
 
 } // !namespace
 
-namespace duk {
-
-std::shared_ptr<JsPlugin> TypeTraits<std::shared_ptr<JsPlugin>>::get(duk::Context *ctx)
-{
-	return std::static_pointer_cast<JsPlugin>(static_cast<Plugin *>(duk::getGlobal<void *>(ctx, PluginGlobal))->shared_from_this());
-}
-
-} // !duk
-
 PluginModule::PluginModule() noexcept
 	: Module("Irccd.Plugin")
 {
@@ -194,18 +194,30 @@
 
 void PluginModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::putGlobal<void *>(plugin.context(), PluginGlobal, &plugin);
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), functions);
-	duk::push(plugin.context(), duk::Object{});
-	duk::putProperty(plugin.context(), -2, "config");
-	duk::push(plugin.context(), duk::Object{});
-	duk::putProperty(plugin.context(), -2, "format");
-	duk::putProperty(plugin.context(), -2, "Plugin");
-	duk::pop(plugin.context());
+	duk_push_pointer(plugin.context(), &plugin);
+	duk_put_global_string(plugin.context(), PluginGlobal);
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_push_object(plugin.context());
+	duk_put_prop_string(plugin.context(), -2, "config");
+	duk_push_object(plugin.context());
+	duk_put_prop_string(plugin.context(), -2, "format");
+	duk_put_prop_string(plugin.context(), -2, "Plugin");
+	duk_pop(plugin.context());
+}
+
+std::shared_ptr<JsPlugin> duk_get_plugin(duk_context *ctx)
+{
+	StackAssert sa(ctx);
+
+	duk_get_global_string(ctx, PluginGlobal);
+	auto plugin = std::static_pointer_cast<JsPlugin>(static_cast<JsPlugin *>(duk_to_pointer(ctx, -1))->shared_from_this());
+	duk_pop(ctx);
+
+	return plugin;
 }
 
 } // !irccd
--- a/lib/irccd/mod-plugin.hpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-plugin.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -24,31 +24,11 @@
  * \brief Irccd.Plugin JavaScript API.
  */
 
-#include "js.hpp"
+#include "duktape.hpp"
 #include "module.hpp"
 
 namespace irccd {
 
-namespace duk {
-
-/**
- * \brief Custom specialization for JsPlugin.
- * \note Use the dedicated get function to get the underlying JsPlugin.
- */
-template <>
-class TypeTraits<std::shared_ptr<JsPlugin>> {
-public:
-	/**
-	 * Get the plugin.
-	 *
-	 * \param ctx the context
-	 * \return the plugin
-	 */
-	IRCCD_EXPORT static std::shared_ptr<JsPlugin> get(duk::Context *ctx);
-};
-
-} // !duk
-
 /**
  * \brief Irccd.Plugin JavaScript API.
  * \ingroup modules
@@ -66,6 +46,14 @@
 	IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override;
 };
 
+/**
+ * Access the plugin stored in this context.
+ *
+ * \param ctx the context
+ * \return the plugin
+ */
+std::shared_ptr<JsPlugin> duk_get_plugin(duk_context *ctx);
+
 } // !irccd
 
 #endif // !IRCCD_MOD_PLUGIN_HPP
--- a/lib/irccd/mod-server.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-server.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -21,6 +21,7 @@
 #include <unordered_map>
 
 #include "irccd.hpp"
+#include "mod-irccd.hpp"
 #include "mod-server.hpp"
 #include "plugin-js.hpp"
 #include "server.hpp"
@@ -30,8 +31,23 @@
 
 namespace {
 
-const std::string Signature("\xff""\xff""irccd-server-ptr");
-const std::string Prototype("\xff""\xff""irccd-server-prototype");
+const char *Signature("\xff""\xff""irccd-server-ptr");
+const char *Prototype("\xff""\xff""irccd-server-prototype");
+
+std::shared_ptr<Server> self(duk_context *ctx)
+{
+	StackAssert sa(ctx);
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, Signature);
+	auto ptr = duk_to_pointer(ctx, -1);
+	duk_pop_2(ctx);
+
+	if (!ptr)
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
+
+	return *static_cast<std::shared_ptr<Server> *>(ptr);
+}
 
 /*
  * Method: Server.cmode(channel, mode)
@@ -43,9 +59,9 @@
  *   - channel, the channel,
  *   - mode, the mode.
  */
-duk::Ret cmode(duk::Context *ctx)
+duk_ret_t cmode(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->cmode(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->cmode(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -60,9 +76,9 @@
  *   - channel, the channel,
  *   - message, the message.
  */
-duk::Ret cnotice(duk::Context *ctx)
+duk_ret_t cnotice(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->cnotice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->cnotice(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -80,29 +96,40 @@
  * sslVerify: true if ssl was verified
  * channels: an array of all channels
  */
-duk::Ret info(duk::Context *ctx)
+duk_ret_t info(duk_context *ctx)
 {
-	auto server = duk::self<std::shared_ptr<Server>>(ctx);
+	auto server = self(ctx);
 
-	duk::push(ctx, duk::Object{});
-	duk::putProperty(ctx, -1, "name", server->name());
-	duk::putProperty(ctx, -1, "host", server->info().host);
-	duk::putProperty(ctx, -1, "port", static_cast<int>(server->info().port));
-	duk::putProperty<bool>(ctx, -1, "ssl", server->info().flags & ServerInfo::Ssl);
-	duk::putProperty<bool>(ctx, -1, "sslVerify", server->info().flags & ServerInfo::SslVerify);
-	duk::putProperty(ctx, -1, "commandChar", server->settings().command);
-	duk::putProperty(ctx, -1, "realname", server->identity().realname);
-	duk::putProperty(ctx, -1, "nickname", server->identity().nickname);
-	duk::putProperty(ctx, -1, "username", server->identity().username);
+	duk_push_object(ctx);
+	duk_push_stdstring(ctx, server->name());
+	duk_put_prop_string(ctx, -2, "name");
+	duk_push_stdstring(ctx, server->info().host);
+	duk_put_prop_string(ctx, -2, "host");
+	duk_push_int(ctx, server->info().port);
+	duk_put_prop_string(ctx, -2, "port");
+	duk_push_boolean(ctx, server->info().flags & ServerInfo::Ssl);
+	duk_put_prop_string(ctx, -2, "ssl");
+	duk_push_boolean(ctx, server->info().flags & ServerInfo::SslVerify);
+	duk_put_prop_string(ctx, -2, "sslVerify");
+	duk_push_stdstring(ctx, server->settings().command);
+	duk_put_prop_string(ctx, -2, "commandChar");
+	duk_push_stdstring(ctx, server->identity().realname);
+	duk_put_prop_string(ctx, -2, "realname");
+	duk_push_stdstring(ctx, server->identity().nickname);
+	duk_put_prop_string(ctx, -2, "nickname");
+	duk_push_stdstring(ctx, server->identity().username);
+	duk_put_prop_string(ctx, -2, "username");
 
 	// Channels.
-	duk::push(ctx, duk::Array{});
+	duk_push_array(ctx);
 
 	int i = 0;
-	for (const auto &channel : server->settings().channels)
-		duk::putProperty(ctx, -1, i++, channel.name);
+	for (const auto &channel : server->settings().channels) {
+		duk_push_stdstring(ctx, channel.name);
+		duk_put_prop_index(ctx, -1, i++);
+	}
 
-	duk::putProperty(ctx, -2, "channels");
+	duk_put_prop_string(ctx, -2, "channels");
 
 	return 1;
 }
@@ -117,9 +144,9 @@
  *   - target, the target to invite,
  *   - channel, the channel.
  */
-duk::Ret invite(duk::Context *ctx)
+duk_ret_t invite(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->invite(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->invite(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -134,9 +161,9 @@
  *   - channel, the channel to join,
  *   - password, the password or undefined to not use.
  */
-duk::Ret join(duk::Context *ctx)
+duk_ret_t join(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->join(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, ""));
+	self(ctx)->join(duk_require_string(ctx, 0), duk_get_string(ctx, 1));
 
 	return 0;
 }
@@ -152,13 +179,9 @@
  *   - channel, the channel,
  *   - reason, the optional reason or undefined to not set.
  */
-duk::Ret kick(duk::Context *ctx)
+duk_ret_t kick(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->kick(
-		duk::require<std::string>(ctx, 0),
-		duk::require<std::string>(ctx, 1),
-		duk::optional<std::string>(ctx, 2, "")
-	);
+	self(ctx)->kick(duk_require_string(ctx, 0), duk_require_string(ctx, 1), duk_get_string(ctx, 2));
 
 	return 0;
 }
@@ -173,9 +196,9 @@
  *   - target, the target or a channel,
  *   - message, the message.
  */
-duk::Ret me(duk::Context *ctx)
+duk_ret_t me(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->me(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->me(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -190,9 +213,9 @@
  *   - target, the target or a channel,
  *   - message, the message.
  */
-duk::Ret message(duk::Context *ctx)
+duk_ret_t message(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->message(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->message(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -206,9 +229,9 @@
  * Arguments:
  *   - mode, the new mode.
  */
-duk::Ret mode(duk::Context *ctx)
+duk_ret_t mode(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->mode(duk::require<std::string>(ctx, 0));
+	self(ctx)->mode(duk_require_string(ctx, 0));
 
 	return 0;
 }
@@ -222,9 +245,9 @@
  * Arguments:
  *   - channel, the channel.
  */
-duk::Ret names(duk::Context *ctx)
+duk_ret_t names(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->names(duk::require<std::string>(ctx, 0));
+	self(ctx)->names(duk_require_string(ctx, 0));
 
 	return 0;
 }
@@ -238,9 +261,9 @@
  * Arguments:
  *   - nickname, the nickname.
  */
-duk::Ret nick(duk::Context *ctx)
+duk_ret_t nick(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->nick(duk::require<std::string>(ctx, 0));
+	self(ctx)->nick(duk_require_string(ctx, 0));
 
 	return 0;
 }
@@ -255,9 +278,9 @@
  *   - target, the target,
  *   - message, the notice message.
  */
-duk::Ret notice(duk::Context *ctx)
+duk_ret_t notice(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->notice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->notice(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -272,9 +295,9 @@
  *   - channel, the channel to leave,
  *   - reason, the optional reason, keep undefined for portability.
  */
-duk::Ret part(duk::Context *ctx)
+duk_ret_t part(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->part(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, ""));
+	self(ctx)->part(duk_require_string(ctx, 0), duk_get_string(ctx, 1));
 
 	return 0;
 }
@@ -288,9 +311,9 @@
  * Arguments:
  *   - raw, the raw message (without terminators).
  */
-duk::Ret send(duk::Context *ctx)
+duk_ret_t send(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->send(duk::require<std::string>(ctx, 0));
+	self(ctx)->send(duk_require_string(ctx, 0));
 
 	return 0;
 }
@@ -305,9 +328,9 @@
  *   - channel, the channel,
  *   - topic, the new topic.
  */
-duk::Ret topic(duk::Context *ctx)
+duk_ret_t topic(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->topic(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	self(ctx)->topic(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	return 0;
 }
@@ -321,9 +344,9 @@
  * Arguments:
  *   - target, the target.
  */
-duk::Ret whois(duk::Context *ctx)
+duk_ret_t whois(duk_context *ctx)
 {
-	duk::self<std::shared_ptr<Server>>(ctx)->whois(duk::require<std::string>(ctx, 0));
+	self(ctx)->whois(duk_require_string(ctx, 0));
 
 	return 0;
 }
@@ -335,12 +358,12 @@
  * Convert the object to std::string, convenience for adding the object
  * as property key.
  *
- * Returns:
+ * duk_ret_turns:
  *   The server name (unique).
  */
-duk::Ret toString(duk::Context *ctx)
+duk_ret_t toString(duk_context *ctx)
 {
-	duk::push(ctx, duk::self<std::shared_ptr<Server>>(ctx)->name());
+	duk_push_stdstring(ctx, self(ctx)->name());
 
 	return 1;
 }
@@ -366,9 +389,10 @@
  * realname: "real name",	(Optional, default: IRC Client Daemon)
  * commandChar: "!",		(Optional, the command char, default: "!")
  */
-duk::Ret constructor(duk::Context *ctx)
+duk_ret_t constructor(duk_context *ctx)
 {
-	if (!duk::isConstructorCall(ctx))
+#if 0
+	if (!isConstructorCall(ctx))
 		return 0;
 
 	std::string name;
@@ -377,37 +401,41 @@
 	ServerSettings settings;
 
 	// Information part.
-	name = duk::getProperty<std::string>(ctx, 0, "name");
-	info.host = duk::getProperty<std::string>(ctx, 0, "host");
-	info.port = duk::optionalProperty<int>(ctx, 0, "port", static_cast<int>(info.port));
-	info.password = duk::optionalProperty<std::string>(ctx, 0, "password", "");
+	name = getProperty<std::string>(ctx, 0, "name");
+	info.host = getProperty<std::string>(ctx, 0, "host");
+	info.port = optionalProperty<int>(ctx, 0, "port", static_cast<int>(info.port));
+	info.password = optionalProperty<std::string>(ctx, 0, "password", "");
 
-	if (duk::optionalProperty<bool>(ctx, 0, "ipv6", false))
+	if (optionalProperty<bool>(ctx, 0, "ipv6", false))
 		info.flags |= ServerInfo::Ipv6;
 
 	// Identity part.
-	identity.nickname = duk::optionalProperty<std::string>(ctx, 0, "nickname", identity.nickname);
-	identity.username = duk::optionalProperty<std::string>(ctx, 0, "username", identity.username);
-	identity.realname = duk::optionalProperty<std::string>(ctx, 0, "realname", identity.realname);
-	identity.ctcpversion = duk::optionalProperty<std::string>(ctx, 0, "version", identity.ctcpversion);
+	identity.nickname = optionalProperty<std::string>(ctx, 0, "nickname", identity.nickname);
+	identity.username = optionalProperty<std::string>(ctx, 0, "username", identity.username);
+	identity.realname = optionalProperty<std::string>(ctx, 0, "realname", identity.realname);
+	identity.ctcpversion = optionalProperty<std::string>(ctx, 0, "version", identity.ctcpversion);
 
 	// Settings part.
-	for (const auto &chan: duk::getProperty<std::vector<std::string>>(ctx, 0, "channels"))
+	for (const auto &chan: getProperty<std::vector<std::string>>(ctx, 0, "channels"))
 		settings.channels.push_back(Server::splitChannel(chan));
 
-	settings.reconnectTries = duk::optionalProperty<int>(ctx, 0, "recoTries", (int)settings.reconnectTries);
-	settings.reconnectDelay = duk::optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.reconnectDelay);
+	settings.reconnectTries = optionalProperty<int>(ctx, 0, "recoTries", (int)settings.reconnectTries);
+	settings.reconnectDelay = optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.reconnectDelay);
 
-	if (duk::optionalProperty<bool>(ctx, 0, "joinInvite", false))
+	if (optionalProperty<bool>(ctx, 0, "joinInvite", false))
 		settings.flags |= ServerSettings::JoinInvite;
-	if (duk::optionalProperty<bool>(ctx, 0, "autoRejoin", false))
+	if (optionalProperty<bool>(ctx, 0, "autoRejoin", false))
 		settings.flags |= ServerSettings::AutoRejoin;
 
 	try {
-		duk::construct(ctx, std::make_shared<Server>(std::move(name), std::move(info), std::move(identity), std::move(settings)));
+		push(ctx, This());
+		pushPointer(ctx, new std::shared_ptr<Server>(std::move(name), std::move(info), std::move(identity), std::move(settings)));
+		putProperty(ctx, -2, Signature);
+		pop(ctx);
 	} catch (const std::exception &ex) {
-		duk::raise(ctx, duk::Error(ex.what()));
+		raise(ctx, Error(ex.what()));
 	}
+#endif
 
 	return 0;
 }
@@ -418,11 +446,12 @@
  *
  * Delete the property.
  */
-duk::Ret destructor(duk::Context *ctx)
+duk_ret_t destructor(duk_context *ctx)
 {
-	delete static_cast<std::shared_ptr<Server> *>(duk::getProperty<void *>(ctx, 0, Signature));
-
-	duk::deleteProperty(ctx, 0, Signature);
+	duk_get_prop_string(ctx, 0, Signature);
+	delete static_cast<std::shared_ptr<Server> *>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+	duk_del_prop_string(ctx, 0, Signature);
 
 	return 0;
 }
@@ -436,9 +465,9 @@
  * Arguments:
  *   - s, the server to add.
  */
-duk::Ret add(duk::Context *ctx)
+duk_ret_t add(duk_context *ctx)
 {
-	duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().add(duk::require<std::shared_ptr<Server>>(ctx, 0));
+	duk_get_irccd(ctx).serverService().add(duk_require_server(ctx, 0));
 
 	return 0;
 }
@@ -451,19 +480,17 @@
  *
  * Arguments:
  *   - name, the server name
- * Returns:
+ * duk_ret_turns:
  *   The server object or undefined if not found.
  */
-duk::Ret find(duk::Context *ctx)
+duk_ret_t find(duk_context *ctx)
 {
-	const auto name = duk::require<std::string>(ctx, 0);
-	const auto irccd = duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd");
+	auto server = duk_get_irccd(ctx).serverService().get(duk_require_string(ctx, 0));
 
-	try {
-		duk::push(ctx, irccd->serverService().require(name));
-	} catch (...) {
+	if (!server)
 		return 0;
-	}
+
+	duk_push_server(ctx, server);
 
 	return 1;
 }
@@ -474,15 +501,17 @@
  *
  * Get the map of all loaded servers.
  *
- * Returns:
+ * duk_ret_turns:
  *   An object with string-to-servers pairs.
  */
-duk::Ret list(duk::Context *ctx)
+duk_ret_t list(duk_context *ctx)
 {
-	duk::push(ctx, duk::Object{});
+	duk_push_object(ctx);
 
-	for (const auto &server : duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().servers())
-		duk::putProperty(ctx, -1, server->name(), server);
+	for (const auto &server : duk_get_irccd(ctx).serverService().servers()) {
+		duk_push_server(ctx, server);
+		duk_put_prop_string(ctx, -2, server->name().c_str());
+	}
 
 	return 1;
 }
@@ -496,79 +525,44 @@
  * Arguments:
  *   - name the server name.
  */
-duk::Ret remove(duk::Context *ctx)
+duk_ret_t remove(duk_context *ctx)
 {
-	duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().remove(duk::require<std::string>(ctx, 0));
+	duk_get_irccd(ctx).serverService().remove(duk_require_string(ctx, 0));
 
 	return 0;
 }
 
-const duk::FunctionMap methods{
-	{ "cmode",	{ cmode,	2		} },
-	{ "cnotice",	{ cnotice,	2		} },
-	{ "info",	{ info,		0		} },
-	{ "invite",	{ invite,	2		} },
-	{ "join",	{ join,		DUK_VARARGS	} },
-	{ "kick",	{ kick,		DUK_VARARGS	} },
-	{ "me",		{ me,		2		} },
-	{ "message",	{ message,	2		} },
-	{ "mode",	{ mode,		1		} },
-	{ "names",	{ names,	1		} },
-	{ "nick",	{ nick,		1		} },
-	{ "notice",	{ notice,	2		} },
-	{ "part",	{ part,		DUK_VARARGS	} },
-	{ "send",	{ send,		1		} },
-	{ "topic",	{ topic,	2		} },
-	{ "whois",	{ whois,	1		} },
-	{ "toString",	{ toString,	0		} }
+const duk_function_list_entry methods[] = {
+	{ "cmode",	cmode,		2		},
+	{ "cnotice",	cnotice,	2		},
+	{ "info",	info,		0		},
+	{ "invite",	invite,		2		},
+	{ "join",	join,		DUK_VARARGS	},
+	{ "kick",	kick,		DUK_VARARGS	},
+	{ "me",		me,		2		},
+	{ "message",	message,	2		},
+	{ "mode",	mode,		1		},
+	{ "names",	names,		1		},
+	{ "nick",	nick,		1		},
+	{ "notice",	notice,		2		},
+	{ "part",	part,		DUK_VARARGS	},
+	{ "send",	send,		1		},
+	{ "topic",	topic,		2		},
+	{ "whois",	whois,		1		},
+	{ "toString",	toString,	0		},
+	{ nullptr,	nullptr,	0		}
 };
 
-const duk::FunctionMap functions{
-	{ "add",	{ add,		1		} },
-	{ "find",	{ find,		1		} },
-	{ "list",	{ list,		0		} },
-	{ "remove",	{ remove,	1		} }
+const duk_function_list_entry functions[] = {
+	{ "add",	add,		1		},
+	{ "find",	find,		1		},
+	{ "list",	list,		0		},
+	{ "remove",	remove,		1		},
+	{ nullptr,	nullptr,	0		}
 };
 
 } // !namespace
 
-namespace duk {
-
-void TypeTraits<std::shared_ptr<Server>>::construct(Context *ctx, std::shared_ptr<Server> server)
-{
-	assert(server);
-
-	duk::StackAssert sa(ctx);
-
-	duk::push(ctx, This());
-	duk::putProperty(ctx, -1, Signature, new std::shared_ptr<Server>(std::move(server)));
-	duk::pop(ctx);
-}
-
-void TypeTraits<std::shared_ptr<Server>>::push(Context *ctx, std::shared_ptr<Server> server)
-{
-	assert(server);
-
-	duk::StackAssert sa(ctx, 1);
-
-	duk::push(ctx, Object());
-	duk::putProperty(ctx, -1, Signature, new std::shared_ptr<Server>(std::move(server)));
-	duk::getGlobal<void>(ctx, Prototype);
-	duk::setPrototype(ctx, -2);
-}
-
-std::shared_ptr<Server> TypeTraits<std::shared_ptr<Server>>::require(Context *ctx, Index index)
-{
-	auto ptr = getProperty<std::shared_ptr<Server> *>(ctx, index, Signature);
-
-	if (!ptr)
-		duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
-
-	return *ptr;
-}
-
-} // !duk
-
 ServerModule::ServerModule() noexcept
 	: Module("Irccd.Server")
 {
@@ -576,20 +570,46 @@
 
 void ServerModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
+
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_c_function(plugin.context(), constructor, 1);
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, methods);
+	duk_push_c_function(plugin.context(), destructor, 1);
+	duk_set_finalizer(plugin.context(), -2);
+	duk_dup_top(plugin.context());
+	duk_get_global_string(plugin.context(), Prototype);
+	duk_put_prop_string(plugin.context(), -2, "prototype");
+	duk_put_prop_string(plugin.context(), -2, "Server");
+	duk_pop(plugin.context());
+}
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function(constructor, 1));
-	duk::put(plugin.context(), functions);
-	duk::push(plugin.context(), duk::Object());
-	duk::put(plugin.context(), methods);
-	duk::push(plugin.context(), duk::Function(destructor, 1));
-	duk::setFinalizer(plugin.context(), -2);
-	duk::dup(plugin.context());
-	duk::putGlobal(plugin.context(), Prototype);
-	duk::putProperty(plugin.context(), -2, "prototype");
-	duk::putProperty(plugin.context(), -2, "Server");
-	duk::pop(plugin.context());
+void duk_push_server(duk_context *ctx, std::shared_ptr<Server> server)
+{
+	assert(ctx);
+	assert(server);
+
+	StackAssert sa(ctx, 1);
+
+	duk_push_object(ctx);
+	duk_push_pointer(ctx, new std::shared_ptr<Server>(std::move(server)));
+	duk_put_prop_string(ctx, -2, Signature);
+	duk_get_global_string(ctx, Prototype);
+	duk_set_finalizer(ctx, -2);
+}
+
+std::shared_ptr<Server> require(duk_context *ctx, duk_idx_t index)
+{
+	if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature))
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
+
+	duk_get_prop_string(ctx, index, Signature);
+	auto file = *static_cast<std::shared_ptr<Server> *>(duk_to_pointer(ctx, -1));
+	duk_pop(ctx);
+	
+	return file;
 }
 
 } // !irccd
--- a/lib/irccd/mod-server.hpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-server.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -24,50 +24,12 @@
  * \brief Irccd.Server JavaScript API.
  */
 
-#include "js.hpp"
+#include "duktape.hpp"
 #include "module.hpp"
 #include "server.hpp"
 
 namespace irccd {
 
-namespace duk {
-
-/**
- * \brief JavaScript binding for Server.
- */
-template <>
-class TypeTraits<std::shared_ptr<Server>> {
-public:
-	/**
-	 * Construct a server.
-	 *
-	 * \pre server != nullptr
-	 * \param ctx the context
-	 * \param server the server
-	 */
-	IRCCD_EXPORT static void construct(Context *ctx, std::shared_ptr<Server> server);
-
-	/**
-	 * Push a server.
-	 *
-	 * \pre server != nullptr
-	 * \param ctx the context
-	 * \param server the server
-	 */
-	IRCCD_EXPORT static void push(Context *ctx, std::shared_ptr<Server> server);
-
-	/**
-	 * Require a server. Raise a JavaScript error if not a Server.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the server
-	 */
-	IRCCD_EXPORT static std::shared_ptr<Server> require(Context *ctx, Index index);
-};
-
-} // !duk
-
 /**
  * \brief Irccd.Server JavaScript API.
  * \ingroup modules
@@ -85,6 +47,24 @@
 	IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override;
 };
 
+/**
+ * Push a server.
+ *
+ * \pre server != nullptr
+ * \param ctx the context
+ * \param server the server
+ */
+IRCCD_EXPORT void duk_push_server(duk_context *ctx, std::shared_ptr<Server> server);
+
+/**
+ * Require a server. Raise a JavaScript error if not a Server.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the server
+ */
+IRCCD_EXPORT std::shared_ptr<Server> duk_require_server(duk_context *ctx, duk_idx_t index);
+
 } // !irccd
 
 #endif // !IRCCD_JS_SERVER_HPP
--- a/lib/irccd/mod-system.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-system.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -47,9 +47,9 @@
  * Returns:
  *   The value.
  */
-int env(duk::Context *ctx)
+duk_ret_t env(duk_context *ctx)
 {
-	duk::push(ctx, sys::env(duk::get<std::string>(ctx, 0)));
+	duk_push_stdstring(ctx, sys::env(duk_get_string(ctx, 0)));
 
 	return 1;
 }
@@ -63,9 +63,9 @@
  * Arguments:
  *   - cmd, the command to execute.
  */
-int exec(duk::Context *ctx)
+duk_ret_t exec(duk_context *ctx)
 {
-	std::system(duk::get<const char *>(ctx, 0));
+	std::system(duk_get_string(ctx, 0));
 
 	return 0;
 }
@@ -79,9 +79,9 @@
  * Returns:
  *   The user home directory.
  */
-int home(duk::Context *ctx)
+duk_ret_t home(duk_context *ctx)
 {
-	duk::push(ctx, sys::home());
+	duk_push_stdstring(ctx, sys::home());
 
 	return 1;
 }
@@ -95,9 +95,9 @@
  * Returns:
  *   The system name.
  */
-int name(duk::Context *ctx)
+duk_ret_t name(duk_context *ctx)
 {
-	duk::push(ctx, sys::name());
+	duk_push_stdstring(ctx, sys::name());
 
 	return 1;
 }
@@ -118,14 +118,14 @@
  * Throws
  *   - Irccd.SystemError on failures.
  */
-int popen(duk::Context *ctx)
+duk_ret_t popen(duk_context *ctx)
 {
-	auto fp = ::popen(duk::require<const char *>(ctx, 0), duk::require<const char *>(ctx, 1));
+	auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
 
 	if (fp == nullptr)
-		duk::raise(ctx, SystemError{});
+		duk_throw(ctx, SystemError());
 
-	duk::push(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); }));
+	duk_push_file(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); }));
 
 	return 1;
 }
@@ -138,9 +138,9 @@
  *
  * Sleep the main loop for the specific delay in seconds.
  */
-int sleep(duk::Context *ctx)
+duk_ret_t sleep(duk_context *ctx)
 {
-	std::this_thread::sleep_for(std::chrono::seconds(duk::get<int>(ctx, 0)));
+	std::this_thread::sleep_for(std::chrono::seconds(duk_get_int(ctx, 0)));
 
 	return 0;
 }
@@ -154,9 +154,9 @@
  * Returns:
  *   The number of milliseconds.
  */
-int ticks(duk::Context *ctx)
+duk_ret_t ticks(duk_context *ctx)
 {
-	duk::push(ctx, static_cast<int>(sys::ticks()));
+	duk_push_int(ctx, sys::ticks());
 
 	return 1;
 }
@@ -167,9 +167,9 @@
  *
  * Sleep the main loop for the specific delay in microseconds.
  */
-int usleep(duk::Context *ctx)
+duk_ret_t usleep(duk_context *ctx)
 {
-	std::this_thread::sleep_for(std::chrono::microseconds(duk::get<int>(ctx, 0)));
+	std::this_thread::sleep_for(std::chrono::microseconds(duk_get_int(ctx, 0)));
 
 	return 0;
 }
@@ -183,9 +183,9 @@
  * Returns:
  *   The system uptime.
  */
-int uptime(duk::Context *ctx)
+duk_ret_t uptime(duk_context *ctx)
 {
-	duk::push<int>(ctx, sys::uptime());
+	duk_push_int(ctx, sys::uptime());
 
 	return 0;
 }
@@ -199,26 +199,26 @@
  * Returns:
  *   The system version.
  */
-int version(duk::Context *ctx)
+duk_ret_t version(duk_context *ctx)
 {
-	duk::push(ctx, sys::version());
+	duk_push_stdstring(ctx, sys::version());
 
 	return 1;
 }
 
-const duk::FunctionMap functions{
-	{ "env",	{ env,		1	} },
-	{ "exec",	{ exec,		1	} },
-	{ "home",	{ home,		0	} },
-	{ "name",	{ name,		0	} },
+const duk_function_list_entry functions[] = {
+	{ "env",	env,		1	},
+	{ "exec",	exec,		1	},
+	{ "home",	home,		0	},
+	{ "name",	name,		0	},
 #if defined(HAVE_POPEN)
-	{ "popen",	{ popen,	2	} }, 
+	{ "popen",	popen,		2	}, 
 #endif
-	{ "sleep",	{ sleep,	1	} },
-	{ "ticks",	{ ticks,	0	} },
-	{ "uptime",	{ uptime,	0	} },
-	{ "usleep",	{ usleep,	1	} },
-	{ "version",	{ version,	0	} }
+	{ "sleep",	sleep,		1	},
+	{ "ticks",	ticks,		0	},
+	{ "uptime",	uptime,		0	},
+	{ "usleep",	usleep,		1	},
+	{ "version",	version,	0	}
 };
 
 } // !namespace
@@ -230,13 +230,13 @@
 
 void SystemModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), functions);
-	duk::putProperty(plugin.context(), -2, "System");
-	duk::pop(plugin.context());
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_put_prop_string(plugin.context(), -2, "System");
+	duk_pop(plugin.context());
 }
 
 } // !irccd
--- a/lib/irccd/mod-timer.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-timer.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -20,6 +20,7 @@
 
 #include "irccd.hpp"
 #include "logger.hpp"
+#include "mod-irccd.hpp"
 #include "mod-timer.hpp"
 #include "mod-plugin.hpp"
 #include "plugin-js.hpp"
@@ -31,39 +32,8 @@
 
 namespace {
 
-const std::string Signature{"\xff""\xff""irccd-timer-ptr"};
-const std::string CallbackTable{"\xff""\xff""irccd-timer-callbacks"};
-
-} // !namespace
-
-namespace duk {
-
-template <>
-class TypeTraits<std::shared_ptr<Timer>> {
-public:
-	static inline void construct(duk::Context *ctx, std::shared_ptr<Timer> timer)
-	{
-		duk::StackAssert sa(ctx);
-
-		duk::push(ctx, duk::This());
-		duk::putProperty<void *>(ctx, -1, Signature, new std::shared_ptr<Timer>(std::move(timer)));
-		duk::pop(ctx);
-	}
-
-	static inline std::shared_ptr<Timer> require(duk::Context *ctx, duk::Index index)
-	{
-		auto ptr = static_cast<std::shared_ptr<Timer> *>(duk::getProperty<void *>(ctx, index, Signature));
-
-		if (!ptr)
-			duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not a Timer object");
-
-		return *ptr;
-	}
-};
-
-} // !duk
-
-namespace {
+const char *Signature("\xff""\xff""irccd-timer-ptr");
+const char *CallbackTable("\xff""\xff""irccd-timer-callbacks");
 
 void handleSignal(std::weak_ptr<JsPlugin> ptr, std::string key)
 {
@@ -72,34 +42,39 @@
 	if (!plugin)
 		return;
 
-	auto irccd = duk::getGlobal<Irccd *>(plugin->context(), "\xff""\xff""irccd");
+	auto &irccd = duk_get_irccd(plugin->context());
 
-	irccd->post([plugin, key] (Irccd &) {
-		duk::StackAssert sa(plugin->context());
+	irccd.post([plugin, key] (Irccd &) {
+		StackAssert sa(plugin->context());
 
-		duk::getGlobal<void>(plugin->context(), CallbackTable);
-		duk::getProperty<void>(plugin->context(), -1, key);
-		duk::remove(plugin->context(), -2);
+		duk_get_global_string(plugin->context(), CallbackTable);
+		duk_get_prop_string(plugin->context(), -1, key.c_str());
+		duk_remove(plugin->context(), -2);
 
-		if (duk::is<duk::Function>(plugin->context(), -1)) {
-			if (duk::pcall(plugin->context()) != 0)
-				log::warning("plugin {}: {}"_format(plugin->name(), duk::exception(plugin->context(), -1).stack));
+		if (duk_is_callable(plugin->context(), -1)) {
+			if (duk_pcall(plugin->context(), 0) != 0)
+				log::warning("plugin {}: {}"_format(plugin->name(), duk_exception(plugin->context(), -1).stack));
 			else
-				duk::pop(plugin->context());
+				duk_pop(plugin->context());
 		} else
-			duk::pop(plugin->context());
+			duk_pop(plugin->context());
 	});
 }
 
+std::shared_ptr<Timer> self(duk_context *ctx)
+{
+	return nullptr;
+}
+
 /*
  * Method: Timer.start()
  * --------------------------------------------------------
  *
  * Start the timer. If the timer is already started the method is a no-op.
  */
-duk::Ret start(duk::Context *ctx)
+duk_ret_t start(duk_context *ctx)
 {
-	auto timer = duk::self<std::shared_ptr<Timer>>(ctx);
+	auto timer = self(ctx);
 
 	if (!timer->isRunning())
 		timer->start();
@@ -113,9 +88,9 @@
  *
  * Stop the timer.
  */
-duk::Ret stop(duk::Context *ctx)
+duk_ret_t stop(duk_context *ctx)
 {
-	auto timer = duk::self<std::shared_ptr<Timer>>(ctx);
+	auto timer = self(ctx);
 
 	if (timer->isRunning())
 		timer->stop();
@@ -123,9 +98,10 @@
 	return 0;
 }
 
-const duk::FunctionMap methods{
-	{ "start",	{ start,	0 } },
-	{ "stop",	{ stop,		0 } }
+const duk_function_list_entry methods[] = {
+	{ "start",	start,		0 },
+	{ "stop",	stop,		0 },
+	{ nullptr,	nullptr,	0 }
 };
 
 /*
@@ -139,56 +115,60 @@
  *   - delay, the interval in milliseconds,
  *   - callback, the function to call.
  */
-duk::Ret constructor(duk::Context *ctx)
+duk_ret_t constructor(duk_context *ctx)
 {
 	// Check parameters.
-	auto type = duk::require<int>(ctx, 0);
-	auto delay = duk::require<int>(ctx, 1);
+	auto type = duk_require_int(ctx, 0);
+	auto delay = duk_require_int(ctx, 1);
 
 	if (type < static_cast<int>(TimerType::Single) || type > static_cast<int>(TimerType::Repeat))
-		duk::raise(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type");
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type");
 	if (delay < 0)
-		duk::raise(ctx, DUK_ERR_TYPE_ERROR, "negative delay given");
-	if (!duk::is<duk::Function>(ctx, 2))
-		duk::raise(ctx, DUK_ERR_TYPE_ERROR, "missing callback function");
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "negative delay given");
+	if (!duk_is_callable(ctx, 2))
+		duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function");
 
 	// Construct the timer in 'this'.
 	auto timer = std::make_shared<Timer>(static_cast<TimerType>(type), delay);
-	auto plugin = duk::TypeTraits<std::shared_ptr<JsPlugin>>::get(ctx);
 	auto hash = std::to_string(reinterpret_cast<std::uintptr_t>(timer.get()));
 
-	timer->onSignal.connect(std::bind(handleSignal, std::weak_ptr<JsPlugin>(plugin), hash));
+	timer->onSignal.connect(std::bind(handleSignal, std::weak_ptr<JsPlugin>(duk_get_plugin(ctx)), hash));
+
+	duk_push_this(ctx);
+	duk_push_pointer(ctx, new std::shared_ptr<Timer>(std::move(timer)));
+	duk_put_prop_string(ctx, -2, Signature);
+	duk_push_string(ctx, hash.c_str());
+	duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key");
 
-	// Set a finalizer that closes the timer.
-	duk::construct(ctx, std::shared_ptr<Timer>(std::move(timer)));
-	duk::push(ctx, duk::This());
-	duk::putProperty(ctx, -1, "\xff""\xff""timer-key", hash);
-	duk::push(ctx, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-		duk::StackAssert sa(ctx);
+#if 0
+	push(ctx, Function{[] (duk_context *ctx) -> duk_ret_t {
+		StackAssert sa(ctx);
 
-		duk::require<std::shared_ptr<Timer>>(ctx, 0)->stop();
-		delete static_cast<std::shared_ptr<Timer> *>(duk::getProperty<void *>(ctx, 0, Signature));
-		duk::getGlobal<void>(ctx, CallbackTable);
-		duk::deleteProperty(ctx, -1, duk::getProperty<std::string>(ctx, 0, "\xff""\xff""timer-key"));
-		duk::pop(ctx);
+		require<std::shared_ptr<Timer>>(ctx, 0)->stop();
+		delete static_cast<std::shared_ptr<Timer> *>(getProperty<void *>(ctx, 0, Signature));
+		getGlobal<void>(ctx, CallbackTable);
+		deleteProperty(ctx, -1, getProperty<std::string>(ctx, 0, "\xff""\xff""timer-key"));
+		pop(ctx);
 		log::debug("plugin: timer destroyed");
 
 		return 0;
 	}, 1});
-	duk::setFinalizer(ctx, -2);
+	setFinalizer(ctx, -2);
+#endif
 
 	// Save a callback function into the callback table.
-	duk::getGlobal<void>(ctx, CallbackTable);
-	duk::dup(ctx, 2);
-	duk::putProperty(ctx, -2, hash);
-	duk::pop(ctx);
+	duk_get_global_string(ctx, CallbackTable);
+	duk_dup(ctx, 2);
+	duk_put_prop_string(ctx, -2, hash.c_str());
+	duk_pop(ctx);
 
 	return 0;
 }
 
-const duk::Map<int> constants{
-	{ "Single",	static_cast<int>(TimerType::Single) },
-	{ "Repeat",	static_cast<int>(TimerType::Repeat) },
+const duk_number_list_entry constants[] = {
+	{ "Single",	static_cast<int>(TimerType::Single)	},
+	{ "Repeat",	static_cast<int>(TimerType::Repeat)	},
+	{ nullptr,	0					} 
 };
 
 } // !namespace
@@ -200,17 +180,18 @@
 
 void TimerModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function{constructor, 3});
-	duk::put(plugin.context(), constants);
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), methods);
-	duk::putProperty(plugin.context(), -2, "prototype");
-	duk::putProperty(plugin.context(), -2, "Timer");
-	duk::pop(plugin.context());
-	duk::putGlobal(plugin.context(), CallbackTable, duk::Object{});
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_c_function(plugin.context(), constructor, 3);
+	duk_put_number_list(plugin.context(), -1, constants);
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, methods);
+	duk_put_prop_string(plugin.context(), -2, "prototype");
+	duk_put_prop_string(plugin.context(), -2, "Timer");
+	duk_pop(plugin.context());
+	duk_push_object(plugin.context());
+	duk_put_global_string(plugin.context(), CallbackTable);
 }
 
 } // !irccd
--- a/lib/irccd/mod-unicode.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-unicode.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -16,7 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "js.hpp"
+#include "duktape.hpp"
 #include "mod-unicode.hpp"
 #include "plugin-js.hpp"
 #include "unicode.hpp"
@@ -34,9 +34,9 @@
  * Returns:
  *   True if the code is in the digit category.
  */
-duk::Ret isDigit(duk::Context *ctx)
+duk_ret_t isDigit(duk_context *ctx)
 {
-	duk::push(ctx, unicode::isdigit(duk::get<int>(ctx, 0)));
+	duk_push_boolean(ctx, unicode::isdigit(duk_get_int(ctx, 0)));
 
 	return 1;
 }
@@ -50,9 +50,9 @@
  * Returns:
  *   True if the code is in the letter category.
  */
-duk::Ret isLetter(duk::Context *ctx)
+duk_ret_t isLetter(duk_context *ctx)
 {
-	duk::push(ctx, unicode::isalpha(duk::get<int>(ctx, 0)));
+	duk_push_boolean(ctx, unicode::isalpha(duk_get_int(ctx, 0)));
 
 	return 1;
 }
@@ -66,9 +66,9 @@
  * Returns:
  *   True if the code is lower case.
  */
-duk::Ret isLower(duk::Context *ctx)
+duk_ret_t isLower(duk_context *ctx)
 {
-	duk::push(ctx, unicode::islower(duk::get<int>(ctx, 0)));
+	duk_push_boolean(ctx, unicode::islower(duk_get_int(ctx, 0)));
 
 	return 1;
 }
@@ -82,9 +82,9 @@
  * Returns:
  *   True if the code is in the space category.
  */
-duk::Ret isSpace(duk::Context *ctx)
+duk_ret_t isSpace(duk_context *ctx)
 {
-	duk::push(ctx, unicode::isspace(duk::get<int>(ctx, 0)));
+	duk_push_boolean(ctx, unicode::isspace(duk_get_int(ctx, 0)));
 
 	return 1;
 }
@@ -98,9 +98,9 @@
  * Returns:
  *   True if the code is title case.
  */
-duk::Ret isTitle(duk::Context *ctx)
+duk_ret_t isTitle(duk_context *ctx)
 {
-	duk::push(ctx, unicode::istitle(duk::get<int>(ctx, 0)));
+	duk_push_boolean(ctx, unicode::istitle(duk_get_int(ctx, 0)));
 
 	return 1;
 }
@@ -114,20 +114,21 @@
  * Returns:
  *   True if the code is upper case.
  */
-duk::Ret isUpper(duk::Context *ctx)
+duk_ret_t isUpper(duk_context *ctx)
 {
-	duk::push(ctx, unicode::isupper(duk::get<int>(ctx, 0)));
+	duk_push_boolean(ctx, unicode::isupper(duk_get_int(ctx, 0)));
 
 	return 1;
 }
 
-const duk::FunctionMap functions{
-	{ "isDigit",		{ isDigit,	1	} },
-	{ "isLetter",		{ isLetter,	1	} },
-	{ "isLower",		{ isLower,	1	} },
-	{ "isSpace",		{ isSpace,	1	} },
-	{ "isTitle",		{ isTitle,	1	} },
-	{ "isUpper",		{ isUpper,	1	} },
+const duk_function_list_entry functions[] = {
+	{ "isDigit",		isDigit,	1	},
+	{ "isLetter",		isLetter,	1	},
+	{ "isLower",		isLower,	1	},
+	{ "isSpace",		isSpace,	1	},
+	{ "isTitle",		isTitle,	1	},
+	{ "isUpper",		isUpper,	1	},
+	{ nullptr,		nullptr,	0	} 
 };
 
 } // !namespace
@@ -139,13 +140,13 @@
 
 void UnicodeModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), functions);
-	duk::putProperty(plugin.context(), -2, "Unicode");
-	duk::pop(plugin.context());
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_put_prop_string(plugin.context(), -2, "Unicode");
+	duk_pop(plugin.context());
 }
 
 } // !irccd
--- a/lib/irccd/mod-util.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/mod-util.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -24,7 +24,7 @@
 
 namespace irccd {
 
-namespace duk {
+namespace {
 
 /**
  * Read parameters for Irccd.Util.format function, the object is defined as follow:
@@ -37,30 +37,22 @@
  *   fieldn: ...
  * }
  */
-template <>
-class TypeTraits<util::Substitution> {
-public:
-	static util::Substitution get(duk::Context *ctx, int index)
-	{
-		util::Substitution params;
+util::Substitution getSubstitution(duk_context *ctx, int index)
+{
+	util::Substitution params;
 
-		if (!duk::is<Object>(ctx, index))
-			return params;
+	if (!duk_is_object(ctx, index))
+		return params;
 
-		duk::enumerate(ctx, index, 0, true, [&] (duk::Context *) {
-			if (duk::get<std::string>(ctx, -2) == "date")
-				params.time = static_cast<time_t>(duk::get<double>(ctx, -1) / 1000);
-			else
-				params.keywords.insert({duk::get<std::string>(ctx, -2), duk::get<std::string>(ctx, -1)});
-		});
+	duk_enumerate(ctx, index, 0, true, [&] (duk_context *) {
+		if (duk_get_stdstring(ctx, -2) == "date")
+			params.time = static_cast<time_t>(duk_get_number(ctx, -1) / 1000);
+		else
+			params.keywords.insert({duk_get_string(ctx, -2), duk_get_string(ctx, -1)});
+	});
 
-		return params;
-	}
-};
-
-} // !duk
-
-namespace {
+	return params;
+}
 
 /*
  * Function: Irccd.Util.format(text, parameters)
@@ -74,12 +66,12 @@
  * Returns:
  *   The converted text.
  */
-duk::Ret format(duk::Context *ctx)
+duk_ret_t format(duk_context *ctx)
 {
 	try {
-		duk::push(ctx, util::format(duk::get<std::string>(ctx, 0), duk::get<util::Substitution>(ctx, 1)));
+		duk_push_stdstring(ctx, util::format(duk_get_stdstring(ctx, 0), getSubstitution(ctx, 1)));
 	} catch (const std::exception &ex) {
-		duk::raise(ctx, duk::SyntaxError(ex.what()));
+		duk_throw(ctx, SyntaxError(ex.what()));
 	}
 
 	return 1;
@@ -96,13 +88,13 @@
  * Returns:
  *   The nickname.
  */
-duk::Ret splituser(duk::Context *ctx)
+duk_ret_t splituser(duk_context *ctx)
 {
-	const char *target = duk::require<const char *>(ctx, 0);
+	auto target = duk_require_string(ctx, 0);
 	char nick[32] = {0};
 
 	irc_target_get_nick(target, nick, sizeof (nick) -1);
-	duk::push(ctx, std::string(nick));
+	duk_push_string(ctx, nick);
 
 	return 1;
 }
@@ -118,21 +110,22 @@
  * Returns:
  *   The hostname.
  */
-duk::Ret splithost(duk::Context *ctx)
+duk_ret_t splithost(duk_context *ctx)
 {
-	const char *target = duk::require<const char *>(ctx, 0);
+	auto target = duk_require_string(ctx, 0);
 	char host[32] = {0};
 
 	irc_target_get_host(target, host, sizeof (host) -1);
-	duk::push(ctx, std::string(host));
+	duk_push_string(ctx, host);
 
 	return 1;
 }
 
-const duk::FunctionMap functions{
-	{ "format",		{ format,	DUK_VARARGS	} },
-	{ "splituser",		{ splituser,	1		} },
-	{ "splithost",		{ splithost,	1		} }
+const duk_function_list_entry functions[] = {
+	{ "format",	format,		DUK_VARARGS	},
+	{ "splituser",	splituser,	1		},
+	{ "splithost",	splithost,	1		},
+	{ nullptr,	nullptr,	0		}
 };
 
 } // !namespace
@@ -144,13 +137,13 @@
 
 void UtilModule::load(Irccd &, JsPlugin &plugin)
 {
-	duk::StackAssert sa(plugin.context());
+	StackAssert sa(plugin.context());
 
-	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Object{});
-	duk::put(plugin.context(), functions);
-	duk::putProperty(plugin.context(), -2, "Util");
-	duk::pop(plugin.context());
+	duk_get_global_string(plugin.context(), "Irccd");
+	duk_push_object(plugin.context());
+	duk_put_function_list(plugin.context(), -1, functions);
+	duk_put_prop_string(plugin.context(), -2, "Util");
+	duk_pop(plugin.context());
 }
 
 } // !irccd
--- a/lib/irccd/net.hpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/net.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -2802,7 +2802,7 @@
 		: m_length(length)
 	{
 		assert(address);
-		assert(length <= sizeof (sockaddr_storage));
+		assert(static_cast<unsigned>(length) <= sizeof (sockaddr_storage));
 
 		std::memset(&m_address, 0, sizeof (sockaddr_storage));
 		std::memcpy(&m_address, address, length);
--- a/lib/irccd/plugin-js.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/plugin-js.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -36,19 +36,19 @@
 
 void JsPlugin::call(const std::string &name, unsigned nargs)
 {
-	duk::getGlobal<void>(m_context, name);
+	duk_get_global_string(m_context, name.c_str());
 
-	if (duk::type(m_context, -1) == DUK_TYPE_UNDEFINED)
+	if (duk_get_type(m_context, -1) == DUK_TYPE_UNDEFINED)
 		// Function not defined, remove the undefined value and all arguments.
-		duk::pop(m_context, nargs + 1);
+		duk_pop_n(m_context, nargs + 1);
 	else {
 		// Call the function and discard the result.
-		duk::insert(m_context, -nargs - 1);
+		duk_insert(m_context, -nargs - 1);
 
-		if (duk::pcall(m_context, nargs) != 0)
-			throw duk::exception(m_context, -1, true);
+		if (duk_pcall(m_context, nargs) != 0)
+			throw duk_exception(m_context, -1, true);
 
-		duk::pop(m_context);
+		duk_pop(m_context);
 	}
 }
 
@@ -60,16 +60,19 @@
 
 void JsPlugin::putVars()
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::putGlobal<void *>(m_context, "\xff""\xff""plugin", this);
-	duk::putGlobal(m_context, "\xff""\xff""name", name());
-	duk::putGlobal(m_context, "\xff""\xff""path", path());
+	duk_push_pointer(m_context, this);
+	duk_get_global_string(m_context, "\xff""\xff""plugin");
+	duk_push_stdstring(m_context, name());
+	duk_put_global_string(m_context, "\xff""\xff""name");
+	duk_push_stdstring(m_context, path());
+	duk_put_global_string(m_context, "\xff""\xff""path");
 }
 
 void JsPlugin::putPath(const std::string &varname, const std::string &append, path::Path type)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
 	bool found = true;
 	std::string foundpath;
@@ -88,43 +91,48 @@
 	if (!found)
 		foundpath = path::clean(path::get(type, path::OwnerSystem) + append);
 
-	duk::getGlobal<void>(m_context, "Irccd");
-	duk::getProperty<void>(m_context, -1, "Plugin");
-	duk::putProperty(m_context, -1, varname, foundpath);
-	duk::pop(m_context, 2);
+	duk_get_global_string(m_context, "Irccd");
+	duk_get_prop_string(m_context, -2, "Plugin");
+	duk_push_stdstring(m_context, foundpath);
+	duk_put_prop_string(m_context, -2, varname.c_str());
+	duk_pop_n(m_context, 2);
 }
 
 void JsPlugin::putConfig(const PluginConfig &config)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
 	// TODO: override dataPath, configPath, cachePath.
 	// TODO: verify more that these values still exist.
 
 	// Store plugin configuration into Irccd.Plugin.config.
-	duk::getGlobal<void>(m_context, "Irccd");
-	duk::getProperty<void>(m_context, -1, "Plugin");
-	duk::getProperty<void>(m_context, -1, "config");
+	duk_get_global_string(m_context, "Irccd");
+	duk_get_prop_string(m_context, -1, "Plugin");
+	duk_get_prop_string(m_context, -1, "config");
 
-	for (const auto &pair : config)
-		duk::putProperty(m_context, -1, pair.first, pair.second);
+	for (const auto &pair : config) {
+		duk_push_stdstring(m_context, pair.second);
+		duk_put_prop_string(m_context, -2, pair.first.c_str());
+	}
 
-	duk::putProperty(m_context, -2, "config");
-	duk::pop(m_context, 2);
+	duk_put_prop_string(m_context, -2, "config");
+	duk_pop_n(m_context, 2);
 }
 
 void JsPlugin::putFormats()
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
+
+	duk_get_global_string(m_context, "Irccd");
+	duk_get_prop_string(m_context, -1, "Plugin");
+	duk_get_prop_string(m_context, -1, "format");
 
-	duk::getGlobal<void>(m_context, "Irccd");
-	duk::getProperty<void>(m_context, -1, "Plugin");
-	duk::getProperty<void>(m_context, -1, "format");
+	for (const auto &pair : formats()) {
+		duk_push_stdstring(m_context, pair.second);
+		duk_put_prop_string(m_context, -1, pair.first.c_str());
+	}
 
-	for (const auto &pair : formats())
-		duk::putProperty(m_context, -1, pair.first, pair.second);
-
-	duk::pop(m_context, 3);
+	duk_pop_n(m_context, 3);
 }
 
 JsPlugin::JsPlugin(std::string name, std::string path, const PluginConfig &config)
@@ -139,13 +147,13 @@
 			     const std::string &mode,
 			     const std::string &arg)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, mode);
-	duk::push(m_context, arg);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, mode);
+	duk_push_stdstring(m_context, arg);
 	call("onChannelMode", 5);
 }
 
@@ -155,12 +163,12 @@
 			       const std::string &channel,
 			       const std::string &notice)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, notice);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, notice);
 	call("onChannelNotice", 4);
 }
 
@@ -170,40 +178,40 @@
 			 const std::string &channel,
 			 const std::string &message)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, message);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, message);
 	call("onCommand", 4);
 }
 
 void JsPlugin::onConnect(Irccd &, const std::shared_ptr<Server> &server)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
+	duk_push_server(m_context, server);
 	call("onConnect", 1);
 }
 
 void JsPlugin::onInvite(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
 	call("onInvite", 3);
 }
 
 void JsPlugin::onJoin(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
 	call("onJoin", 3);
 }
 
@@ -214,19 +222,19 @@
 		      const std::string &target,
 		      const std::string &reason)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, target);
-	duk::push(m_context, reason);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, target);
+	duk_push_stdstring(m_context, reason);
 	call("onKick", 5);
 }
 
 void JsPlugin::onLoad(Irccd &irccd)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
 	/*
 	 * Duktape currently emit useless warnings when a file do
@@ -235,9 +243,8 @@
 #if defined(HAVE_STAT)
 	struct stat st;
 
-	if (::stat(path().c_str(), &st) < 0) {
+	if (::stat(path().c_str(), &st) < 0)
 		throw std::runtime_error(std::strerror(errno));
-	}
 #endif
 
 	/*
@@ -251,26 +258,28 @@
 	putPath("cachePath", "plugin/" + name(), path::PathCache);
 
 	// Try to load the file (does not call onLoad yet).
-	if (duk::pevalFile(m_context, path()) != 0)
-		throw duk::exception(m_context, -1, true);
+	if (duk_peval_file(m_context, path().c_str()) != 0)
+		throw duk_exception(m_context, -1, true);
 
-	duk::pop(m_context);
+	duk_pop(m_context);
 
 	putConfig(config());
 	putFormats();
 
 	// Read metadata .
-	duk::getGlobal<void>(m_context, "info");
+	duk_get_global_string(m_context, "info");
 
-	if (duk::type(m_context, -1) == DUK_TYPE_OBJECT) {
-		setAuthor(duk::optionalProperty<std::string>(m_context, -1, "author", author()));
-		setLicense(duk::optionalProperty<std::string>(m_context, -1, "license", license()));
-		setSummary(duk::optionalProperty<std::string>(m_context, -1, "summary", summary()));
-		setVersion(duk::optionalProperty<std::string>(m_context, -1, "version", version()));
+	if (duk_get_type(m_context, -1) == DUK_TYPE_OBJECT) {
+		// TODO: bring back
+#if 0
+		setAuthor(optionalProperty<std::string>(m_context, -1, "author", author()));
+		setLicense(optionalProperty<std::string>(m_context, -1, "license", license()));
+		setSummary(optionalProperty<std::string>(m_context, -1, "summary", summary()));
+		setVersion(optionalProperty<std::string>(m_context, -1, "version", version()));
+#endif
 	}
 
-	duk::pop(m_context);
-
+	duk_pop(m_context);
 	call("onLoad", 0);
 }
 
@@ -280,12 +289,12 @@
 			 const std::string &channel,
 			 const std::string &message)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, message);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, message);
 	call("onMessage", 4);
 }
 
@@ -295,52 +304,53 @@
 		    const std::string &channel,
 		    const std::string &message)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, message);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, message);
 	call("onMe", 4);
 }
 
 void JsPlugin::onMode(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, mode);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, mode);
 	call("onMode", 3);
 }
 
 void JsPlugin::onNames(Irccd &, const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &names)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, channel);
-	duk::push(m_context, names);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, channel);
+	// TODO
+	// duk_push_stdstring(m_context, names);
 	call("onNames", 3);
 }
 
 void JsPlugin::onNick(Irccd &, const std::shared_ptr<Server> &server, const std::string &oldnick, const std::string &newnick)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, oldnick);
-	duk::push(m_context, newnick);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, oldnick);
+	duk_push_stdstring(m_context, newnick);
 	call("onNick", 3);
 }
 
 void JsPlugin::onNotice(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, notice);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, notice);
 	call("onNotice", 3);
 }
 
@@ -350,12 +360,12 @@
 		      const std::string &channel,
 		      const std::string &reason)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, reason);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, reason);
 	call("onPart", 4);
 }
 
@@ -364,11 +374,11 @@
 		       const std::string &origin,
 		       const std::string &message)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, message);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, message);
 	call("onQuery", 3);
 }
 
@@ -377,17 +387,17 @@
 			      const std::string &origin,
 			      const std::string &message)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, message);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, message);
 	call("onQueryCommand", 3);
 }
 
 void JsPlugin::onReload(Irccd &)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
 	call("onReload");
 }
@@ -398,18 +408,18 @@
 		       const std::string &channel,
 		       const std::string &topic)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, origin);
-	duk::push(m_context, channel);
-	duk::push(m_context, topic);
+	duk_push_server(m_context, server);
+	duk_push_stdstring(m_context, origin);
+	duk_push_stdstring(m_context, channel);
+	duk_push_stdstring(m_context, topic);
 	call("onTopic", 4);
 }
 
 void JsPlugin::onUnload(Irccd &irccd)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
 	call("onUnload");
 
@@ -419,15 +429,20 @@
 
 void JsPlugin::onWhois(Irccd &, const std::shared_ptr<Server> &server, const ServerWhois &whois)
 {
-	duk::StackAssert sa(m_context);
+	StackAssert sa(m_context);
 
-	duk::push(m_context, server);
-	duk::push(m_context, duk::Object{});
-	duk::putProperty(m_context, -1, "nickname", whois.nick);
-	duk::putProperty(m_context, -1, "username", whois.user);
-	duk::putProperty(m_context, -1, "realname", whois.realname);
-	duk::putProperty(m_context, -1, "host", whois.host);
-	duk::putProperty(m_context, 1, "channels", whois.channels);
+	duk_push_server(m_context, server);
+	duk_push_object(m_context);
+	duk_push_stdstring(m_context, whois.nick);
+	duk_put_prop_string(m_context, -2, "nickname");
+	duk_push_stdstring(m_context, whois.user);
+	duk_put_prop_string(m_context, -2, "username");
+	duk_push_stdstring(m_context, whois.realname);
+	duk_put_prop_string(m_context, -2, "realname");
+	duk_push_stdstring(m_context, whois.host);
+	duk_put_prop_string(m_context, -2, "host");
+	// TODO
+	// duk_put_prop_string(m_context, -2, "channels", whois.channels);
 	call("onWhois", 2);
 }
 
--- a/lib/irccd/plugin-js.hpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/plugin-js.hpp	Fri Jun 03 13:28:10 2016 +0200
@@ -24,7 +24,7 @@
  * \brief JavaScript plugins for irccd.
  */
 
-#include "js.hpp"
+#include "duktape.hpp"
 #include "path.hpp"
 #include "plugin.hpp"
 #include "signals.hpp"
@@ -40,7 +40,7 @@
 class JsPlugin : public Plugin {
 private:
 	// JavaScript context
-	duk::UniqueContext m_context;
+	UniqueContext m_context;
 
 	// Store loaded modules.
 	std::vector<std::shared_ptr<Module>> m_modules;
@@ -68,7 +68,7 @@
 	 *
 	 * \return the context
 	 */
-	inline duk::UniqueContext &context() noexcept
+	inline UniqueContext &context() noexcept
 	{
 		return m_context;
 	}
--- a/lib/irccd/server-event.cpp	Tue May 31 22:33:32 2016 +0200
+++ b/lib/irccd/server-event.cpp	Fri Jun 03 13:28:10 2016 +0200
@@ -54,7 +54,7 @@
 		// TODO: get generic error.
 		try {
 			m_exec(*plugin);
-		} catch (const duk::Exception &info) {
+		} catch (const Exception &info) {
 			log::warning() << "plugin " << plugin->name() << ": error: " << info.what() << std::endl;
 
 			if (!info.fileName.empty())