changeset 179:ef527409e638

Irccd: update JavaScript code
author David Demelier <markand@malikania.fr>
date Tue, 31 May 2016 21:03:01 +0200
parents 084081b24024
children b0909b31eccb
files cmake/internal/sysconfig.hpp.in irccd/main.cpp lib/irccd/js.hpp lib/irccd/mod-directory.cpp lib/irccd/mod-elapsed-timer.cpp lib/irccd/mod-elapsed-timer.hpp 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/plugin-js.cpp lib/irccd/plugin-js.hpp lib/irccd/server-event.cpp tests/js-elapsedtimer/main.cpp tests/js-file/main.cpp tests/js-irccd/main.cpp tests/js-logger/main.cpp tests/js-system/CMakeLists.txt tests/js-system/main.cpp tests/js-util/main.cpp
diffstat 29 files changed, 1580 insertions(+), 920 deletions(-) [+]
line wrap: on
line diff
--- a/cmake/internal/sysconfig.hpp.in	Thu May 26 21:20:46 2016 +0200
+++ b/cmake/internal/sysconfig.hpp.in	Tue May 31 21:03:01 2016 +0200
@@ -37,6 +37,7 @@
 #define IRCCD_VERSION_MAJOR	@IRCCD_VERSION_MAJOR@
 #define IRCCD_VERSION_MINOR	@IRCCD_VERSION_MINOR@
 #define IRCCD_VERSION_PATCH	@IRCCD_VERSION_PATCH@
+#define IRCCD_VERSION		"@IRCCD_VERSION@"
 
 /*
  * System identification.
--- a/irccd/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/irccd/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -31,6 +31,7 @@
 #endif
 
 #include <csignal>
+#include <iostream>
 
 #include <format.h>
 
@@ -61,7 +62,8 @@
 	log::warning() << "  -f, --foreground        do not run as a daemon\n";
 	log::warning() << "      --help              show this help\n";
 	log::warning() << "  -p, --plugin name       load a specific plugin\n";
-	log::warning() << "  -v, --verbose           be verbose" << std::endl;
+	log::warning() << "  -v, --verbose           be verbose\n";
+	log::warning() << "      --version           show the version\n";
 	std::exit(1);
 }
 
@@ -103,20 +105,22 @@
 			{ "-p",			true	},
 			{ "--plugin",		true	},
 			{ "-v",			false	},
-			{ "--verbose",		false	}
+			{ "--verbose",		false	},
+			{ "--version",		false	}
 		};
 
 		result = parser::read(argc, argv, options);
 
 		for (const auto &pair : result) {
-			if (pair.first == "--help") {
+			if (pair.first == "--help")
 				usage();
 				// NOTREACHED
+			if (pair.first == "--version") {
+				std::cout << IRCCD_VERSION << std::endl;
+				std::exit(1);
 			}
-
-			if (pair.first == "-v" || pair.first == "--verbose") {
+			if (pair.first == "-v" || pair.first == "--verbose")
 				log::setVerbose(true);
-			}
 		}
 	} catch (const std::exception &ex) {
 		log::warning() << sys::programName() << ": " << ex.what() << std::endl;
@@ -143,17 +147,15 @@
 
 void loadPid(const std::string &path)
 {
-	if (path.empty()) {
+	if (path.empty())
 		return;
-	}
 
 	try {
 #if defined(HAVE_GETPID)
 		std::ofstream out(path, std::ofstream::trunc);
 
-		if (!out) {
+		if (!out)
 			throw std::runtime_error("could not open pidfile {}: {}"_format(path, std::strerror(errno)));
-		}
 
 		log::debug() << "irccd: pid written in " << path << std::endl;
 		out << getpid() << std::endl;
@@ -168,13 +170,12 @@
 void loadGid(const std::string gid)
 {
 	try {
-		if (!gid.empty()) {
+		if (!gid.empty())
 #if defined(HAVE_SETGID)
 			sys::setGid(gid);
 #else
 			throw std::runtime_error(" gid option not supported on this platform");
 #endif
-		}
 	} catch (const std::exception &ex) {
 		log::warning() << "irccd: " << ex.what() << std::endl;
 	}
@@ -183,13 +184,12 @@
 void loadUid(const std::string &uid)
 {
 	try {
-		if (!uid.empty()) {
+		if (!uid.empty())
 #if defined(HAVE_SETUID)
 			sys::setUid(uid);
 #else
 			throw std::runtime_error("uid option not supported on this platform");
 #endif
-		}
 	} catch (const std::exception &ex) {
 		log::warning() << "irccd: " << ex.what() << std::endl;
 	}
@@ -199,9 +199,8 @@
 {
 	try {
 #if defined(HAVE_DAEMON)
-		if (options.count("-f") == 0 && options.count("--foreground") == 0 && !foreground) {
+		if (options.count("-f") == 0 && options.count("--foreground") == 0 && !foreground)
 			daemon(1, 0);
-		}
 #else
 		if (options.count("-f") > 0 || options.count("--foreground") > 0 || foreground)
 			throw std::runtime_error("foreground option not supported on this platform");
@@ -233,19 +232,16 @@
 	loadForeground(config.isForeground(), options);
 
 	// [transport]
-	for (const auto &transport : config.loadTransports()) {
+	for (const auto &transport : config.loadTransports())
 		instance->transportService().add(transport);
-	}
 
 	// [server] section.
-	for (const auto &server : config.loadServers()) {
+	for (const auto &server : config.loadServers())
 		instance->serverService().add(server);
-	}
 
 	// [rule] section.
-	for (const auto &rule : config.loadRules()) {
+	for (const auto &rule : config.loadRules())
 		instance->ruleService().add(rule);
-	}
 
 	// [plugin] section.
 	config.loadPlugins(*instance);
--- a/lib/irccd/js.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/js.hpp	Tue May 31 21:03:01 2016 +0200
@@ -22,6 +22,7 @@
 /**
  * \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.
@@ -29,7 +30,435 @@
  * 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>
@@ -47,13 +476,40 @@
  */
 namespace duk {
 
-class Context;
+/**
+ * \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;
 
-using CodePoint = duk_codepoint_t;
-using ContextPtr = duk_context *;
-using Index = duk_idx_t;
-using Ret = duk_ret_t;
-using Size = duk_size_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
@@ -69,7 +525,7 @@
 class StackAssert {
 #if !defined(NDEBUG)
 private:
-	ContextPtr m_context;
+	Context *m_context;
 	unsigned m_expected;
 	unsigned m_begin;
 #endif
@@ -83,7 +539,7 @@
 	 * \param ctx the context
 	 * \param expected the size expected relative to the already existing values
 	 */
-	inline StackAssert(ContextPtr ctx, unsigned expected = 0) noexcept
+	inline StackAssert(Context *ctx, unsigned expected = 0) noexcept
 #if !defined(NDEBUG)
 		: m_context(ctx)
 		, m_expected(expected)
@@ -104,106 +560,129 @@
 	inline ~StackAssert() noexcept
 	{
 #if !defined(NDEBUG)
-		assert((unsigned)duk_get_top(m_context) - m_begin == m_expected);
+		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 Empty class tag for push() function.
+ * \brief Special type for duk::TypeTraits.
  */
 class Object {
 };
 
 /**
  * \class Array
- * \brief Empty class tag for push() function.
+ * \brief Special type for duk::TypeTraits.
  */
 class Array {
 };
 
 /**
  * \class Global
- * \brief Empty class tag to push the global object.
+ * \brief Special type for duk::TypeTraits.
  */
 class Global {
 };
 
 /**
  * \class Undefined
- * \brief Empty class tag to push undefined to the stack.
+ * \brief Special type for duk::TypeTraits.
  */
 class Undefined {
 };
 
 /**
  * \class Null
- * \brief Empty class tag to push null to the stack.
+ * \brief Special type for duk::TypeTraits.
  */
 class Null {
 };
 
 /**
  * \class This
- * \brief Empty class tag to push this binding to the stack.
+ * \brief Special type for duk::TypeTraits.
  */
 class This {
 };
 
 /**
- * \class RawPointer
- * \brief Push a non-managed pointer to Duktape, the pointer will never be deleted.
- * \note For a managed pointer with prototype, see Pointer
- */
-template <typename T>
-class RawPointer {
-public:
-	/**
-	 * The pointer to push.
-	 */
-	T *object;
-};
-
-/**
- * \brief Manage shared_ptr from C++ and JavaScript
- *
- * This class allowed you to push and retrieve shared_ptr from C++ and JavaScript without taking care of ownership
- * and deletion.
- *
- */
-template <typename T>
-class Shared {
-public:
-	/**
-	 * The shared object.
-	 */
-	std::shared_ptr<T> object;
-};
-
-/**
- * \brief Manage pointers from C++ and JavaScript
- *
- * This class allowed you to push and retrieve C++ pointers from C++ and JavaScript. The object will be deleted when
- * the JavaScript garbage collectors collect them so never store a pointer created with this.
- *
- * The only requirement is to have the function `void prototype(Context &ctx)` in your class T.
- */
-template <typename T>
-class Pointer {
-public:
-	/**
-	 * The object.
-	 */
-	T *object{nullptr};
-
-	Pointer(T *o)
-		: object(o)
-	{
-	}
-};
-
-/**
  * \class Function
  * \brief Duktape/C function definition.
  *
@@ -221,7 +700,13 @@
 	 */
 	duk_idx_t nargs{0};
 
-	Function(duk_c_function f, duk_idx_t n = 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)
 	{
@@ -229,23 +714,23 @@
 };
 
 /**
- * Map of functions to set on an object.
+ * \brief Map of functions.
  */
 using FunctionMap = std::unordered_map<std::string, Function>;
 
 /**
- * Map of string to type, ideal for setting constants like enums.
+ * \brief Map of any type.
  */
-template <typename Type>
-using Map = std::unordered_map<std::string, Type>;
+template <typename T>
+using Map = std::unordered_map<std::string, T>;
 
 /**
- * \class ErrorInfo
+ * \class Exception
  * \brief Error description.
  *
  * This class fills the fields got in an Error object.
  */
-class ErrorInfo : public std::exception {
+class Exception : public std::exception {
 public:
 	std::string name;		//!< name of error
 	std::string message;		//!< error message
@@ -265,69 +750,35 @@
 };
 
 /**
- * \class TypeTraits
- * \brief Type information to implement new types in JavaScript's context.
- *
- * This class depending on your needs may have the following functions:
- *
- * - `static void construct(Context &ctx, Type value)`
- * - `static Type get(Context &ctx, int index)`
- * - `static bool is(Context &ctx, int index)`
- * - `static Type optional(Context &ctx, int index, Type defaultValue)`
- * - `static void push(Context &ctx, Type value)`
- * - `static Type require(Context &ctx, int index)`
- *
- * The `construct` function is used in Context::construct to build a new value as this (e.g. constructors).
- *
- * The `get` function is used in Context::get, Context::getProperty, Context::getGlobal to retrieve a value from the
- * stack.
- *
- * The `is` function is used in Context::is to check if the value on the stack is of type `Type`.
- *
- * The `optional` function is used in Context::optional to get a value or a replacement if not applicable.
- *
- * The `push` function is used in Context::push to usually create a new value on the stack but some specializations
- * may not (e.g. FunctionMap).
- *
- * The `require` function is used in Context::require to get a value from the stack or raise a JavaScript exception if
- * not applicable.
- *
- * This class is fully specialized for: `bool`, `const char *`, `double`, `int`, `std::string`.
- *
- * It is also partially specialized for : `Global`, `Object`, `Array`, `Undefined`, `Null`, `std::vector<Type>`.
- */
-template <typename Type>
-class TypeTraits {
-};
-
-/**
- * \class Context
  * \brief RAII based Duktape handler.
  *
  * This class is implicitly convertible to duk_context for convenience.
  */
-class Context {
+class UniqueContext {
 private:
 	using Deleter = void (*)(duk_context *);
 	using Handle = std::unique_ptr<duk_context, Deleter>;
 
 	Handle m_handle;
 
-	Context(const Context &) = delete;
-	Context &operator=(const Context &) = delete;
-	Context(const Context &&) = delete;
-	Context &operator=(const Context &&) = delete;
+	UniqueContext(const UniqueContext &) = delete;
+	UniqueContext &operator=(const UniqueContext &) = delete;
 
 public:
 	/**
 	 * Create default context.
 	 */
-	inline 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
@@ -346,34 +797,48 @@
 	{
 		return m_handle.get();
 	}
+
+	/**
+	 * Default move assignment operator.
+	 *
+	 * \return this
+	 */
+	UniqueContext &operator=(Context &&) noexcept = delete;
 };
 
 /**
- * Get the error object when a JavaScript error has been thrown (e.g. eval failure).
+ * \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 index the index
- * \return the information
+ * \param size the requested size
+ * \return the pointer
  */
-inline ErrorInfo error(ContextPtr ctx, int index)
+inline void *alloc(Context *ctx, Size size)
 {
-	ErrorInfo error;
-
-	index = duk_normalize_index(ctx, index);
+	return duk_alloc(ctx, size);
+}
 
-	duk_get_prop_string(ctx, index, "name");
-	error.name = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "message");
-	error.message = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "fileName");
-	error.fileName = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "lineNumber");
-	error.lineNumber = duk_to_int(ctx, -1);
-	duk_get_prop_string(ctx, index, "stack");
-	error.stack = duk_to_string(ctx, -1);
-	duk_pop_n(ctx, 5);
-
-	return error;
+/**
+ * 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);
 }
 
 /**
@@ -382,7 +847,7 @@
  * \param ctx the context
  * \param index the index
  */
-inline void base64Decode(ContextPtr ctx, Index index)
+inline void base64Decode(Context *ctx, Index index)
 {
 	duk_base64_decode(ctx, index);
 }
@@ -392,10 +857,11 @@
  *
  * \param ctx the context
  * \param index the index
+ * \return the base64 string
  */
-inline void base64Encode(ContextPtr ctx, Index index)
+inline std::string base64Encode(Context *ctx, Index index)
 {
-	duk_base64_encode(ctx, index);
+	return duk_base64_encode(ctx, index);
 }
 
 /**
@@ -404,7 +870,7 @@
  * \param ctx the context
  * \param nargs the number of arguments
  */
-inline void call(ContextPtr ctx, Index nargs = 0)
+inline void call(Context *ctx, Index nargs = 0)
 {
 	duk_call(ctx, nargs);
 }
@@ -415,7 +881,7 @@
  * \param ctx the context
  * \param nargs the number of arguments
  */
-inline void callMethod(ContextPtr ctx, Index nargs = 0)
+inline void callMethod(Context *ctx, Index nargs = 0)
 {
 	duk_call_method(ctx, nargs);
 }
@@ -427,7 +893,7 @@
  * \param index the object index
  * \param nargs the number of arguments
  */
-inline void callProperty(ContextPtr ctx, Index index, Index nargs = 0)
+inline void callProperty(Context *ctx, Index index, Index nargs = 0)
 {
 	duk_call_prop(ctx, index, nargs);
 }
@@ -438,8 +904,9 @@
  * \param ctx the context
  * \param index the index
  * \param charOffset the offset
+ * \return the code point
  */
-inline CodePoint charCodeAt(ContextPtr ctx, Index index, Size charOffset)
+inline duk_codepoint_t charCodeAt(Context *ctx, Index index, duk_size_t charOffset)
 {
 	return duk_char_code_at(ctx, index, charOffset);
 }
@@ -451,9 +918,9 @@
  * \param extra the extra space
  * \return true if space is available
  */
-inline bool checkStack(ContextPtr ctx, Index extra)
+inline bool checkStack(Context *ctx, Index extra)
 {
-	return duk_check_stack(ctx, extra);
+	return duk_check_stack(ctx, extra) != 0;
 }
 
 /**
@@ -463,9 +930,9 @@
  * \param top the extra space
  * \return true if space is available
  */
-inline bool checkStackTop(ContextPtr ctx, Index top)
+inline bool checkStackTop(Context *ctx, Index top)
 {
-	return duk_check_stack_top(ctx, top);
+	return duk_check_stack_top(ctx, top) != 0;
 }
 
 /**
@@ -476,9 +943,9 @@
  * \param type the desired type
  * \return true if object is given type
  */
-inline bool checkType(ContextPtr ctx, Index index, int type)
+inline bool checkType(Context *ctx, Index index, int type)
 {
-	return duk_check_type(ctx, index, type);
+	return duk_check_type(ctx, index, type) != 0;
 }
 
 /**
@@ -489,9 +956,9 @@
  * \param mask the desired mask
  * \return true if object is one of the type
  */
-inline bool checkTypeMask(ContextPtr ctx, Index index, unsigned mask)
+inline bool checkTypeMask(Context *ctx, Index index, unsigned mask)
 {
-	return duk_check_type_mask(ctx, index, mask);
+	return duk_check_type_mask(ctx, index, mask) != 0;
 }
 
 /**
@@ -500,7 +967,7 @@
  * \param ctx the context
  * \param objIndex the object index
  */
-inline void compact(ContextPtr ctx, Index objIndex)
+inline void compact(Context *ctx, Index objIndex)
 {
 	duk_compact(ctx, objIndex);
 }
@@ -511,7 +978,7 @@
  * \param ctx the context
  * \param count the number of values
  */
-inline void concat(ContextPtr ctx, Index count)
+inline void concat(Context *ctx, Index count)
 {
 	duk_concat(ctx, count);
 }
@@ -519,21 +986,34 @@
 /**
  * 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(ContextPtr ctx, Index from, Index to)
+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(ContextPtr ctx, Index index, unsigned flags)
+inline void defineProperty(Context *ctx, Index index, unsigned flags)
 {
 	duk_def_prop(ctx, index, flags);
 }
@@ -541,44 +1021,48 @@
 /**
  * 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(ContextPtr ctx, Index index)
+inline bool deleteProperty(Context *ctx, Index index)
 {
-	return duk_del_prop(ctx, 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(ContextPtr ctx, Index index, unsigned position)
+inline bool deleteProperty(Context *ctx, Index index, unsigned position)
 {
-	return duk_del_prop_index(ctx, index, 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(ContextPtr ctx, Index index, const std::string &name)
+inline bool deleteProperty(Context *ctx, Index index, const std::string &name)
 {
-	return duk_del_prop_string(ctx, index, name.c_str());
+	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(ContextPtr ctx, int index = -1)
+inline void dup(Context *ctx, int index = -1)
 {
 	duk_dup(ctx, index);
 }
@@ -591,9 +1075,9 @@
  * \param index2 the second value
  * \return true if they equal
  */
-inline bool equals(ContextPtr ctx, Index index1, Index index2)
+inline bool equals(Context *ctx, Index index1, Index index2)
 {
-	return duk_equals(ctx, index1, index2);
+	return duk_equals(ctx, index1, index2) != 0;
 }
 
 /**
@@ -601,7 +1085,7 @@
  *
  * \param ctx the context
  */
-inline void eval(ContextPtr ctx)
+inline void eval(Context *ctx)
 {
 	duk_eval(ctx);
 }
@@ -613,12 +1097,9 @@
  * \param path the path
  * \param result true to get the result at the top of the stack
  */
-inline void evalFile(ContextPtr ctx, const std::string &path, bool result = true)
+inline void evalFile(Context *ctx, const std::string &path, bool result = true)
 {
-	if (result)
-		duk_eval_file(ctx, path.c_str());
-	else
-		duk_eval_file_noresult(ctx, path.c_str());
+	return result ? duk_eval_file(ctx, path.c_str()) : duk_eval_file_noresult(ctx, path.c_str());
 }
 
 /**
@@ -628,12 +1109,9 @@
  * \param src the source script
  * \param result true to get the result at the top of the stack
  */
-inline void evalString(ContextPtr ctx, const std::string &src, bool result = true)
+inline void evalString(Context *ctx, const std::string &src, bool result = true)
 {
-	if (result)
-		duk_eval_string(ctx, src.c_str());
-	else
-		duk_eval_string_noresult(ctx, src.c_str());
+	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).
@@ -641,7 +1119,7 @@
  * \param ctx the context
  * \param flags the flags
  */
-inline void gc(ContextPtr ctx, unsigned flags = 0)
+inline void gc(Context *ctx, unsigned flags = 0)
 {
 	duk_gc(ctx, flags);
 }
@@ -653,9 +1131,9 @@
  * \param index the object index
  * \return true if has
  */
-inline bool hasProperty(ContextPtr ctx, Index index)
+inline bool hasProperty(Context *ctx, Index index)
 {
-	return duk_has_prop(ctx, index);
+	return duk_has_prop(ctx, index) != 0;
 }
 
 /**
@@ -666,9 +1144,9 @@
  * \param position the property index
  * \return true if has
  */
-inline bool hasProperty(ContextPtr ctx, Index index, unsigned position)
+inline bool hasProperty(Context *ctx, Index index, unsigned position)
 {
-	return duk_has_prop_index(ctx, index, position);
+	return duk_has_prop_index(ctx, index, position) != 0;
 }
 
 /**
@@ -679,9 +1157,9 @@
  * \param name the property name
  * \return true if has
  */
-inline bool hasProperty(ContextPtr ctx, int index, const std::string &name)
+inline bool hasProperty(Context *ctx, int index, const std::string &name)
 {
-	return duk_has_prop_string(ctx, index, name.c_str());
+	return duk_has_prop_string(ctx, index, name.c_str()) != 0;
 }
 
 /**
@@ -691,7 +1169,7 @@
  * \param to the destination
  * \note Wrapper of duk_insert
  */
-inline void insert(ContextPtr ctx, Index to)
+inline void insert(Context *ctx, Index to)
 {
 	duk_insert(ctx, to);
 }
@@ -704,9 +1182,20 @@
  * \param idx2 the instance requested
  * \return true if idx1 is instance of idx2
  */
-inline bool instanceof(ContextPtr ctx, Index idx1, Index idx2)
+inline bool instanceof(Context *ctx, Index idx1, Index idx2)
 {
-	return duk_instanceof(ctx, idx1, 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;
 }
 
 /**
@@ -715,7 +1204,7 @@
  * \param ctx the context
  * \param count the number of values
  */
-inline void join(ContextPtr ctx, Index count)
+inline void join(Context *ctx, Index count)
 {
 	duk_join(ctx, count);
 }
@@ -726,7 +1215,7 @@
  * \param ctx the context
  * \param index the index
  */
-inline void jsonDecode(ContextPtr ctx, Index index)
+inline void jsonDecode(Context *ctx, Index index)
 {
 	duk_json_decode(ctx, index);
 }
@@ -736,10 +1225,11 @@
  *
  * \param ctx the context
  * \param index the index
+ * \return the JSON string
  */
-inline void jsonEncode(ContextPtr ctx, Index index)
+inline std::string jsonEncode(Context *ctx, Index index)
 {
-	duk_json_encode(ctx, index);
+	return duk_json_encode(ctx, index);
 }
 
 /**
@@ -747,8 +1237,9 @@
  *
  * \param ctx the context
  * \param index the index
+ * \return the absolute index
  */
-inline Index normalizeIndex(ContextPtr ctx, Index index)
+inline Index normalizeIndex(Context *ctx, Index index)
 {
 	return duk_normalize_index(ctx, index);
 }
@@ -758,18 +1249,45 @@
  *
  * \param ctx the context
  * \param nargs the number of arguments
+ * \return non zero on failure
  */
-inline int pcall(ContextPtr ctx, Index nargs = 0)
+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(ContextPtr ctx)
+inline int peval(Context *ctx)
 {
 	return duk_peval(ctx);
 }
@@ -780,8 +1298,9 @@
  * \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(ContextPtr ctx, const std::string &path, bool result = true)
+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());
 }
@@ -792,8 +1311,9 @@
  * \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(ContextPtr ctx, const std::string &src, bool result = true)
+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());
 }
@@ -804,18 +1324,53 @@
  * \param ctx the context
  * \param count the number of values to pop
  */
-inline void pop(ContextPtr ctx, Index count = 1)
+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(ContextPtr ctx, Index index)
+inline void remove(Context *ctx, Index index)
 {
 	duk_remove(ctx, index);
 }
@@ -826,7 +1381,7 @@
  * \param ctx the context
  * \param index the value to replace by the value at the top of the stack
  */
-inline void replace(ContextPtr ctx, Index index)
+inline void replace(Context *ctx, Index index)
 {
 	duk_replace(ctx, index);
 }
@@ -835,9 +1390,9 @@
  * Wrapper for [duk_set_finalizer](http://duktape.org/api.html#duk_set_finalizer).
  *
  * \param ctx the context
- * \param index the object index
+ * \param index the value index
  */
-inline void setFinalizer(ContextPtr ctx, Index index)
+inline void setFinalizer(Context *ctx, Index index)
 {
 	duk_set_finalizer(ctx, index);
 }
@@ -848,7 +1403,7 @@
  * \param ctx the context
  * \param index the value index
  */
-inline void setPrototype(ContextPtr ctx, Index index)
+inline void setPrototype(Context *ctx, Index index)
 {
 	duk_set_prototype(ctx, index);
 }
@@ -860,7 +1415,7 @@
  * \param index1 the first index
  * \param index2 the second index
  */
-inline void swap(ContextPtr ctx, Index index1, Index index2)
+inline void swap(Context *ctx, Index index1, Index index2)
 {
 	duk_swap(ctx, index1, index2);
 }
@@ -871,7 +1426,7 @@
  * \param ctx the context
  * \param index the index
  */
-inline void swapTop(ContextPtr ctx, Index index)
+inline void swapTop(Context *ctx, Index index)
 {
 	duk_swap_top(ctx, index);
 }
@@ -882,50 +1437,127 @@
  * \param ctx the context
  * \return the stack size
  */
-inline int top(ContextPtr ctx) noexcept
+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 idnex
+ * \param index the index
  * \return the type
  */
-inline int type(ContextPtr ctx, Index index) noexcept
+inline int type(Context *ctx, Index index)
 {
 	return duk_get_type(ctx, index);
 }
 
-/*
- * Push / Get / Require / Is / Optional
- * ----------------------------------------------------------
+/**
+ * \}
+ */
+
+/**
+ * \name Extended functions
+ * \brief Extended functions for libjs.
  *
- * The following functions are used to push, get or check values from the stack. They use specialization
- * of TypeTraits class.
+ * The following functions are largely modified or extensions to Duktape.
+ */
+
+/**
+ * \{
  */
 
 /**
- * Push a value into the stack. Calls TypeTraits<T>::push(*this, value);
+ * 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(ContextPtr ctx, Type &&value)
+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(ContextPtr ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0))
+inline auto get(Context *ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0))
 {
 	return TypeTraits<Type>::get(ctx, index);
 }
@@ -933,11 +1565,12 @@
 /**
  * Require a type at the specified index.
  *
+ * \param ctx the context
  * \param index the index
  * \return the value
  */
 template <typename Type>
-inline auto require(ContextPtr ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0))
+inline auto require(Context *ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0))
 {
 	return TypeTraits<Type>::require(ctx, index);
 }
@@ -947,11 +1580,12 @@
  *
  * 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(ContextPtr ctx, int index)
+inline bool is(Context *ctx, int index)
 {
 	return TypeTraits<T>::is(ctx, index);
 }
@@ -962,33 +1596,28 @@
  *
  * 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(ContextPtr ctx, int index, Type &&defaultValue)
+inline auto optional(Context *ctx, int index, Type &&defaultValue)
 {
 	return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue));
 }
 
-/*
- * Properties management
- * ----------------------------------------------------------
- *
- * The following functions are used to read or set properties on objects or globals also using TypeTraits.
- */
-
 /**
  * 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(ContextPtr ctx, int index, const std::string &name) -> decltype(get<Type>(ctx, 0))
+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);
@@ -1000,13 +1629,14 @@
 /**
  * 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(ContextPtr ctx, int index, int position) -> decltype(get<Type>(ctx, 0))
+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);
@@ -1018,12 +1648,13 @@
 /**
  * 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(ContextPtr ctx, int index, const std::string &name)
+inline void getProperty(Context *ctx, int index, const std::string &name)
 {
 	duk_get_prop_string(ctx, index, name.c_str());
 }
@@ -1031,12 +1662,13 @@
 /**
  * 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(ContextPtr ctx, int index, int position)
+inline void getProperty(Context *ctx, int index, int position)
 {
 	duk_get_prop_index(ctx, index, position);
 }
@@ -1044,6 +1676,7 @@
 /**
  * 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
@@ -1051,7 +1684,7 @@
  * \note The stack is unchanged
  */
 template <typename Type, typename DefaultValue>
-inline auto optionalProperty(ContextPtr ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def)))
+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));
@@ -1063,6 +1696,7 @@
 /**
  * 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
@@ -1070,7 +1704,7 @@
  * \note The stack is unchanged
  */
 template <typename Type, typename DefaultValue>
-inline auto optionalProperty(ContextPtr ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def)))
+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));
@@ -1082,13 +1716,14 @@
 /**
  * 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(ContextPtr ctx, int index, const std::string &name, Type &&value)
+void putProperty(Context *ctx, int index, const std::string &name, Type &&value)
 {
 	index = duk_normalize_index(ctx, index);
 
@@ -1099,13 +1734,14 @@
 /**
  * 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(ContextPtr ctx, int index, int position, Type &&value)
+void putProperty(Context *ctx, int index, int position, Type &&value)
 {
 	index = duk_normalize_index(ctx, index);
 
@@ -1114,35 +1750,14 @@
 }
 
 /**
- * Put the value that is at the top of the stack as property to the object.
- *
- * \param index the object index
- * \param name the property name
- */
-inline void putProperty(ContextPtr ctx, int index, const std::string &name)
-{
-	duk_put_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Put the value that is at the top of the stack to the object as index.
- *
- * \param index the object index
- * \param position the position in the object
- */
-inline void putProperty(ContextPtr ctx, int index, int position)
-{
-	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(ContextPtr ctx, const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(ctx, 0))
+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);
@@ -1153,9 +1768,12 @@
 
 /**
  * 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(ContextPtr ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) noexcept
+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());
 }
@@ -1163,11 +1781,12 @@
 /**
  * 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(ContextPtr ctx, const std::string &name, Type&& 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());
@@ -1176,30 +1795,25 @@
 /**
  * Put the value at the top of the stack as global property.
  *
+ * \param ctx the context
  * \param name the property name
  */
-inline void putGlobal(ContextPtr ctx, const std::string &name)
+inline void putGlobal(Context *ctx, const std::string &name)
 {
 	duk_put_global_string(ctx, name.c_str());
 }
 
-/*
- * Extra functions
- * ----------------------------------------------------------
- *
- * The following functions are implemented for convenience and do not exists in the native Duktape API.
- */
-
 /**
  * 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(ContextPtr ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
+void enumerate(Context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
 {
 	duk_enum(ctx, index, flags);
 
@@ -1214,13 +1828,14 @@
 /**
  * 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(ContextPtr ctx) -> decltype(TypeTraits<T>::get(ctx, 0))
+inline auto self(Context *ctx) -> decltype(TypeTraits<T>::require(ctx, 0))
 {
 	duk_push_this(ctx);
-	decltype(TypeTraits<T>::get(ctx, 0)) value = TypeTraits<T>::get(ctx, -1);
+	decltype(TypeTraits<T>::require(ctx, 0)) value = TypeTraits<T>::require(ctx, -1);
 	duk_pop(ctx);
 
 	return value;
@@ -1229,123 +1844,35 @@
 /**
  * Throw an ECMAScript exception.
  *
+ * \param ctx the context
  * \param ex the exception
  */
 template <typename Exception>
-void raise(ContextPtr ctx, const Exception &ex)
+void raise(Context *ctx, const Exception &ex)
 {
 	ex.raise(ctx);
 }
 
 /**
- * Wrapper for duk_throw.
- *
- * \param ctx the context
- */
-inline void raise(ContextPtr ctx)
-{
-	duk_throw(ctx);
-}
-
-/**
- * Wrapper for 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(ContextPtr ctx, int type, const char *fmt, Args&&... args)
-{
-	duk_error(ctx, type, fmt, std::forward<Args>(args)...);
-}
-
-/**
- * Wrapper for duk_new.
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void create(ContextPtr ctx, int nargs = 0)
-{
-	duk_new(ctx, nargs);
-}
-
-/**
  * 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(ContextPtr ctx, T &&value)
+inline void construct(Context *ctx, T &&value)
 {
 	TypeTraits<std::decay_t<T>>::construct(ctx, std::forward<T>(value));
 }
 
 /**
- * Sign the given object with the name from T.
- *
- * This is automatically done for when constructing/pushing object with Shared and Pointer helpers, however you need
- * to manually add it when using inheritance.
+ * \}
  */
-template <typename T>
-inline void sign(ContextPtr ctx, Index index)
-{
-	StackAssert sa(ctx, 0);
-
-	index = duk_normalize_index(ctx, index);
-
-	duk_push_string(ctx, TypeTraits<T>::name().c_str());
-	duk_push_boolean(ctx, true);
-	duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE);
-
-	/* Do for inherited classes */
-	for (const std::string &parent : TypeTraits<T>::inherits()) {
-		duk_push_string(ctx, parent.c_str());
-		duk_push_boolean(ctx, true);
-		duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE);
-	}
-}
-
-/**
- * Check if the object at the given index is signed by T or raise TypeError if not.
- *
- * \param ctx the context
- * \param index the index
- * \see sign
- */
-template <typename T>
-inline void checkSignature(ContextPtr ctx, Index index)
-{
-	StackAssert sa(ctx, 0);
-
-	if (!is<Object>(ctx, index) || !getProperty<bool>(ctx, index, TypeTraits<T>::name()))
-		raise(ctx, DUK_ERR_TYPE_ERROR, "invalid this binding");
-}
-
-/**
- * Tells if the object at the specified index is of type T.
- *
- * \param ctx the context
- * \param index the index
- */
-template <typename T>
-inline bool isSigned(ContextPtr ctx, Index index)
-{
-	StackAssert sa(ctx, 0);
-
-	return is<Object>(ctx, index) && getProperty<bool>(ctx, index, TypeTraits<T>::name());
-}
-
-/* ------------------------------------------------------------------
- * Exception handling
- * ------------------------------------------------------------------ */
 
 /**
  * \class Error
@@ -1387,7 +1914,7 @@
 	 * \note the default implementation search for the global variables
 	 * \param ctx the context
 	 */
-	virtual void raise(ContextPtr ctx) const noexcept
+	virtual void raise(Context *ctx) const
 	{
 		duk_error(ctx, m_type, "%s", m_message.c_str());
 	}
@@ -1495,10 +2022,6 @@
 	}
 };
 
-/* ------------------------------------------------------------------
- * Standard overloads for TypeTraits<T>
- * ------------------------------------------------------------------ */
-
 /**
  * \class TypeTraits<int>
  * \brief Default implementation for int.
@@ -1515,7 +2038,7 @@
 	 * \param index the index
 	 * \return the integer
 	 */
-	static inline int get(ContextPtr ctx, int index)
+	static inline int get(Context *ctx, int index)
 	{
 		return duk_get_int(ctx, index);
 	}
@@ -1527,9 +2050,9 @@
 	 * \param index the index
 	 * \return true if integer
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_number(ctx, index);
+		return duk_is_number(ctx, index) != 0;
 	}
 
 	/**
@@ -1540,7 +2063,7 @@
 	 * \param defaultValue the defaultValue
 	 * \return the integer or defaultValue
 	 */
-	static inline int optional(ContextPtr ctx, int index, int defaultValue)
+	static inline int optional(Context *ctx, int index, int defaultValue)
 	{
 		return is(ctx, index) ? get(ctx, index) : defaultValue;
 	}
@@ -1551,7 +2074,7 @@
 	 * \param ctx the context
 	 * \param value the value
 	 */
-	static inline void push(ContextPtr ctx, int value)
+	static inline void push(Context *ctx, int value)
 	{
 		duk_push_int(ctx, value);
 	}
@@ -1563,7 +2086,7 @@
 	 * \param index the index
 	 * \return the integer
 	 */
-	static inline int require(ContextPtr ctx, int index)
+	static inline int require(Context *ctx, int index)
 	{
 		return duk_require_int(ctx, index);
 	}
@@ -1585,9 +2108,9 @@
 	 * \param index the index
 	 * \return the boolean
 	 */
-	static inline bool get(ContextPtr ctx, int index)
+	static inline bool get(Context *ctx, int index)
 	{
-		return duk_get_boolean(ctx, index);
+		return duk_get_boolean(ctx, index) != 0;
 	}
 
 	/**
@@ -1597,9 +2120,9 @@
 	 * \param index the index
 	 * \return true if boolean
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_boolean(ctx, index);
+		return duk_is_boolean(ctx, index) != 0;
 	}
 
 	/**
@@ -1610,7 +2133,7 @@
 	 * \param defaultValue the defaultValue
 	 * \return the boolean or defaultValue
 	 */
-	static inline bool optional(ContextPtr ctx, int index, bool defaultValue)
+	static inline bool optional(Context *ctx, int index, bool defaultValue)
 	{
 		return is(ctx, index) ? get(ctx, index) : defaultValue;
 	}
@@ -1621,7 +2144,7 @@
 	 * \param ctx the context
 	 * \param value the value
 	 */
-	static inline void push(ContextPtr ctx, bool value)
+	static inline void push(Context *ctx, bool value)
 	{
 		duk_push_boolean(ctx, value);
 	}
@@ -1633,9 +2156,9 @@
 	 * \param index the index
 	 * \return the boolean
 	 */
-	static inline bool require(ContextPtr ctx, int index)
+	static inline bool require(Context *ctx, int index)
 	{
-		return duk_require_boolean(ctx, index);
+		return duk_require_boolean(ctx, index) != 0;
 	}
 };
 
@@ -1655,7 +2178,7 @@
 	 * \param index the index
 	 * \return the double
 	 */
-	static inline double get(ContextPtr ctx, int index)
+	static inline double get(Context *ctx, int index)
 	{
 		return duk_get_number(ctx, index);
 	}
@@ -1667,9 +2190,9 @@
 	 * \param index the index
 	 * \return true if double
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_number(ctx, index);
+		return duk_is_number(ctx, index) != 0;
 	}
 
 	/**
@@ -1680,7 +2203,7 @@
 	 * \param defaultValue the defaultValue
 	 * \return the double or defaultValue
 	 */
-	static inline double optional(ContextPtr ctx, int index, double defaultValue)
+	static inline double optional(Context *ctx, int index, double defaultValue)
 	{
 		return is(ctx, index) ? get(ctx, index) : defaultValue;
 	}
@@ -1691,7 +2214,7 @@
 	 * \param ctx the context
 	 * \param value the value
 	 */
-	static inline void push(ContextPtr ctx, double value)
+	static inline void push(Context *ctx, double value)
 	{
 		duk_push_number(ctx, value);
 	}
@@ -1703,7 +2226,7 @@
 	 * \param index the index
 	 * \return the double
 	 */
-	static inline double require(ContextPtr ctx, int index)
+	static inline double require(Context *ctx, int index)
 	{
 		return duk_require_number(ctx, index);
 	}
@@ -1727,7 +2250,7 @@
 	 * \param index the index
 	 * \return the string
 	 */
-	static inline std::string get(ContextPtr ctx, int index)
+	static inline std::string get(Context *ctx, int index)
 	{
 		duk_size_t size;
 		const char *text = duk_get_lstring(ctx, index, &size);
@@ -1742,9 +2265,9 @@
 	 * \param index the index
 	 * \return true if string
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_string(ctx, index);
+		return duk_is_string(ctx, index) != 0;
 	}
 
 	/**
@@ -1755,7 +2278,7 @@
 	 * \param defaultValue the defaultValue
 	 * \return the string or defaultValue
 	 */
-	static inline std::string optional(ContextPtr ctx, int index, std::string defaultValue)
+	static inline std::string optional(Context *ctx, int index, std::string defaultValue)
 	{
 		return is(ctx, index) ? get(ctx, index) : defaultValue;
 	}
@@ -1766,7 +2289,7 @@
 	 * \param ctx the context
 	 * \param value the value
 	 */
-	static inline void push(ContextPtr ctx, const std::string &value)
+	static inline void push(Context *ctx, const std::string &value)
 	{
 		duk_push_lstring(ctx, value.c_str(), value.length());
 	}
@@ -1778,7 +2301,7 @@
 	 * \param index the index
 	 * \return the string
 	 */
-	static inline std::string require(ContextPtr ctx, int index)
+	static inline std::string require(Context *ctx, int index)
 	{
 		duk_size_t size;
 		const char *text = duk_require_lstring(ctx, index, &size);
@@ -1803,7 +2326,7 @@
 	 * \param index the index
 	 * \return the string
 	 */
-	static inline const char *get(ContextPtr ctx, int index)
+	static inline const char *get(Context *ctx, int index)
 	{
 		return duk_get_string(ctx, index);
 	}
@@ -1815,9 +2338,9 @@
 	 * \param index the index
 	 * \return true if string
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_string(ctx, index);
+		return duk_is_string(ctx, index) != 0;
 	}
 
 	/**
@@ -1828,7 +2351,7 @@
 	 * \param defaultValue the defaultValue
 	 * \return the integer or defaultValue
 	 */
-	static inline const char *optional(ContextPtr ctx, int index, const char *defaultValue)
+	static inline const char *optional(Context *ctx, int index, const char *defaultValue)
 	{
 		return is(ctx, index) ? get(ctx, index) : defaultValue;
 	}
@@ -1839,7 +2362,7 @@
 	 * \param ctx the context
 	 * \param value the value
 	 */
-	static inline void push(ContextPtr ctx, const char *value)
+	static inline void push(Context *ctx, const char *value)
 	{
 		duk_push_string(ctx, value);
 	}
@@ -1851,19 +2374,89 @@
 	 * \param index the index
 	 * \return the string
 	 */
-	static inline const char *require(ContextPtr ctx, int index)
+	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<RawPointer<T>> {
+class TypeTraits<T *> {
 public:
 	/**
 	 * Get a pointer, return nullptr if not a pointer.
@@ -1872,7 +2465,7 @@
 	 * \param index the index
 	 * \return the pointer
 	 */
-	static inline T *get(ContextPtr ctx, int index)
+	static inline T *get(Context *ctx, int index)
 	{
 		return static_cast<T *>(duk_to_pointer(ctx, index));
 	}
@@ -1884,9 +2477,9 @@
 	 * \param index the index
 	 * \return true if pointer
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_pointer(ctx, index);
+		return duk_is_pointer(ctx, index) != 0;
 	}
 
 	/**
@@ -1897,9 +2490,9 @@
 	 * \param defaultValue the defaultValue
 	 * \return the pointer or defaultValue
 	 */
-	static inline T *optional(ContextPtr ctx, int index, RawPointer<T> defaultValue)
+	static inline T *optional(Context *ctx, int index, T *defaultValue)
 	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue.object;
+		return is(ctx, index) ? get(ctx, index) : defaultValue;
 	}
 
 	/**
@@ -1908,9 +2501,9 @@
 	 * \param ctx the context
 	 * \param value the value
 	 */
-	static inline void push(ContextPtr ctx, const RawPointer<T> &value)
+	static inline void push(Context *ctx, T *value)
 	{
-		duk_push_pointer(ctx, value.object);
+		duk_push_pointer(ctx, value);
 	}
 
 	/**
@@ -1920,7 +2513,7 @@
 	 * \param index the index
 	 * \return the pointer
 	 */
-	static inline T *require(ContextPtr ctx, int index)
+	static inline T *require(Context *ctx, int index)
 	{
 		return static_cast<T *>(duk_require_pointer(ctx, index));
 	}
@@ -1944,9 +2537,9 @@
 	 * \param index the value index
 	 * \return true if the value is callable
 	 */
-	static bool is(ContextPtr ctx, Index index)
+	static bool is(Context *ctx, Index index)
 	{
-		return duk_is_callable(ctx, index);
+		return duk_is_callable(ctx, index) != 0;
 	}
 
 	/**
@@ -1956,7 +2549,7 @@
 	 * \param ctx the context
 	 * \param fn the function
 	 */
-	static void push(ContextPtr ctx, Function fn)
+	static void push(Context *ctx, Function fn)
 	{
 		duk_push_c_function(ctx, fn.function, fn.nargs);
 	}
@@ -1966,7 +2559,7 @@
  * \class TypeTraits<FunctionMap>
  * \brief Put the functions to the object at the top of the stack.
  *
- * Provides: push.
+ * Provides: put.
  */
 template <>
 class TypeTraits<FunctionMap> {
@@ -1977,7 +2570,7 @@
 	 * \param ctx the context
 	 * \param map the map of function
 	 */
-	static inline void push(ContextPtr ctx, const FunctionMap &map)
+	static void put(Context *ctx, const FunctionMap &map)
 	{
 		StackAssert sa(ctx, 0);
 
@@ -2004,9 +2597,9 @@
 	 * \param index the index
 	 * \return true if object
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_object(ctx, index);
+		return duk_is_object(ctx, index) != 0;
 	}
 
 	/**
@@ -2014,7 +2607,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	static inline void push(ContextPtr ctx, const Object &)
+	static inline void push(Context *ctx, const Object &)
 	{
 		duk_push_object(ctx);
 	}
@@ -2036,9 +2629,9 @@
 	 * \param index the index
 	 * \return true if array
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_array(ctx, index);
+		return duk_is_array(ctx, index) != 0;
 	}
 
 	/**
@@ -2046,7 +2639,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	static inline void push(ContextPtr ctx, const Array &)
+	static inline void push(Context *ctx, const Array &)
 	{
 		duk_push_array(ctx);
 	}
@@ -2068,9 +2661,9 @@
 	 * \param index the index
 	 * \return true if undefined
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_undefined(ctx, index);
+		return duk_is_undefined(ctx, index) != 0;
 	}
 
 	/**
@@ -2078,7 +2671,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	static inline void push(ContextPtr ctx, const Undefined &)
+	static inline void push(Context *ctx, const Undefined &)
 	{
 		duk_push_undefined(ctx);
 	}
@@ -2100,9 +2693,9 @@
 	 * \param index the index
 	 * \return true if null
 	 */
-	static inline bool is(ContextPtr ctx, int index)
+	static inline bool is(Context *ctx, int index)
 	{
-		return duk_is_null(ctx, index);
+		return duk_is_null(ctx, index) != 0;
 	}
 
 	/**
@@ -2110,7 +2703,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	static inline void push(ContextPtr ctx, const Null &)
+	static inline void push(Context *ctx, const Null &)
 	{
 		duk_push_null(ctx);
 	}
@@ -2129,7 +2722,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	static inline void push(ContextPtr ctx, const This &)
+	static inline void push(Context *ctx, const This &)
 	{
 		duk_push_this(ctx);
 	}
@@ -2149,7 +2742,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	static inline void push(ContextPtr ctx, const Global &)
+	static inline void push(Context *ctx, const Global &)
 	{
 		duk_push_global_object(ctx);
 	}
@@ -2158,7 +2751,7 @@
 /**
  * \brief Push a map of key-value pair as objects.
  *
- * Provides: push.
+ * Provides: push, put.
  *
  * This class is convenient for settings constants such as enums, string and such.
  */
@@ -2172,9 +2765,26 @@
 	 * \param map the values
 	 * \note You need an object at the top of the stack before calling this function
 	 */
-	static void push(ContextPtr ctx, const std::unordered_map<std::string, T> &map)
+	static void push(Context *ctx, const std::unordered_map<std::string, T> &map)
 	{
-		StackAssert sa(ctx, 0);
+		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);
@@ -2186,7 +2796,7 @@
 /**
  * \brief Push or get vectors as JavaScript arrays.
  *
- * Provides: get, push.
+ * Provides: get, push, put.
  */
 template <typename T>
 class TypeTraits<std::vector<T>> {
@@ -2198,7 +2808,7 @@
 	 * \param index the array index
 	 * \return the array or empty array if the value is not an array
 	 */
-	static std::vector<T> get(ContextPtr ctx, int index)
+	static std::vector<T> get(Context *ctx, int index)
 	{
 		StackAssert sa(ctx, 0);
 
@@ -2207,10 +2817,10 @@
 		if (!duk_is_array(ctx, -1))
 			return result;
 
-		int total = duk_get_length(ctx, index);
+		size_t total = duk_get_length(ctx, index);
 
-		for (int i = 0; i < total; ++i)
-			result.push_back(getProperty<T>(ctx, index, i));
+		for (size_t i = 0; i < total; ++i)
+			result.push_back(getProperty<T>(ctx, index, static_cast<int>(i)));
 
 		return result;
 	}
@@ -2221,11 +2831,26 @@
 	 * \param ctx the context
 	 * \param array the values
 	 */
-	static void push(ContextPtr ctx, const std::vector<T> &array)
+	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) {
@@ -2235,167 +2860,6 @@
 	}
 };
 
-/**
- * \brief Implementation of managed shared_ptr
- * \see Shared
- */
-template <typename T>
-class TypeTraits<Shared<T>> {
-private:
-	static void apply(ContextPtr ctx, std::shared_ptr<T> value)
-	{
-		StackAssert sa(ctx, 0);
-
-		sign<T>(ctx, -1);
-
-		duk_push_pointer(ctx, new std::shared_ptr<T>(std::move(value)));
-		duk_put_prop_string(ctx, -2, "\xff""\xff""js-shared-ptr");
-		duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret {
-			duk_get_prop_string(ctx, 0, "\xff""\xff""js-shared-ptr");
-			delete static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1));
-			duk_pop(ctx);
-			duk_push_null(ctx);
-			duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr");
-
-			return 0;
-		}, 1);
-		duk_set_finalizer(ctx, -2);
-	}
-
-public:
-	/**
-	 * Construct the shared_ptr as this.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static void construct(ContextPtr ctx, Shared<T> value)
-	{
-		StackAssert sa(ctx, 0);
-
-		duk_push_this(ctx);
-		apply(ctx, std::move(value.object));
-		duk_pop(ctx);
-	}
-
-	/**
-	 * Push a managed shared_ptr as object.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static void push(ContextPtr ctx, Shared<T> value)
-	{
-		StackAssert sa(ctx, 1);
-
-		duk_push_object(ctx);
-		apply(ctx, value.object);
-		TypeTraits<T>::prototype(ctx);
-		duk_set_prototype(ctx, -2);
-	}
-
-	/**
-	 * Get a managed shared_ptr from the stack.
-	 *
-	 * \param ctx the context
-	 * \param index the object index
-	 * \return the shared_ptr
-	 */
-	static std::shared_ptr<T> get(ContextPtr ctx, int index)
-	{
-		StackAssert sa(ctx, 0);
-
-		checkSignature<T>(ctx, index);
-
-		duk_get_prop_string(ctx, index, "\xff""\xff""js-shared-ptr");
-		std::shared_ptr<T> value = *static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1));
-		duk_pop(ctx);
-
-		return value;
-	}
-};
-
-/**
- * \brief Implementation of managed pointers
- * \see Pointer
- */
-template <typename T>
-class TypeTraits<Pointer<T>> {
-private:
-	static void apply(ContextPtr ctx, T *value)
-	{
-		StackAssert sa(ctx, 0);
-
-		sign<T>(ctx, -1);
-
-		duk_push_pointer(ctx, value);
-		duk_put_prop_string(ctx, -2, "\xff""\xff""js-ptr");
-		duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret {
-			duk_get_prop_string(ctx, 0, "\xff""\xff""js-ptr");
-			delete static_cast<T *>(duk_to_pointer(ctx, -1));
-			duk_pop(ctx);
-			duk_push_null(ctx);
-			duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr");
-
-			return 0;
-		}, 1);
-		duk_set_finalizer(ctx, -2);
-	}
-
-public:
-	/**
-	 * Construct the pointer as this.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static void construct(ContextPtr ctx, Pointer<T> value)
-	{
-		StackAssert sa(ctx, 0);
-
-		duk_push_this(ctx);
-		apply(ctx, value.object);
-		duk_pop(ctx);
-	}
-
-	/**
-	 * Push a managed pointer as object.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static void push(ContextPtr ctx, Pointer<T> value)
-	{
-		StackAssert sa(ctx, 1);
-
-		duk_push_object(ctx);
-		apply(ctx, value.object);
-		TypeTraits<T>::prototype(ctx);
-		duk_set_prototype(ctx, -2);
-	}
-
-	/**
-	 * Get a managed pointer from the stack.
-	 *
-	 * \param ctx the context
-	 * \param index the object index
-	 * \return the pointer
-	 * \warning Do not store the pointer into the C++ side, the object can be deleted at any time
-	 */
-	static T *get(ContextPtr ctx, int index)
-	{
-		StackAssert sa(ctx, 0);
-
-		checkSignature<T>(ctx, index);
-
-		duk_get_prop_string(ctx, index, "\xff""\xff""js-ptr");
-		T *value = static_cast<T *>(duk_to_pointer(ctx, -1));
-		duk_pop(ctx);
-
-		return value;
-	}
-};
-
 } // !duk
 
 } // !irccd
--- a/lib/irccd/mod-directory.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-directory.cpp	Tue May 31 21:03:01 2016 +0200
@@ -36,7 +36,7 @@
 
 namespace {
 
-std::string path(duk::ContextPtr ctx)
+std::string path(duk::Context *ctx)
 {
 	duk::push(ctx, duk::This{});
 	duk::getProperty<void>(ctx, -1, "path");
@@ -125,7 +125,7 @@
  *
  * The patternIndex is the argument where to test if the argument is a regex or a string.
  */
-duk::Ret find(duk::ContextPtr ctx, std::string base, bool recursive, int patternIndex)
+duk::Ret find(duk::Context *ctx, std::string base, bool recursive, int patternIndex)
 {
 	base = path::clean(base);
 
@@ -165,7 +165,7 @@
  * - Directory.remove
  * - Directory.prototype.remove
  */
-duk::Ret remove(duk::ContextPtr ctx, const std::string &path, bool recursive)
+duk::Ret remove(duk::Context *ctx, const std::string &path, bool recursive)
 {
 	if (!fs::isDirectory(path))
 		duk::raise(ctx, SystemError(EINVAL, "not a directory"));
@@ -197,7 +197,7 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodFind(duk::ContextPtr ctx)
+duk::Ret methodFind(duk::Context *ctx)
 {
 	return find(ctx, path(ctx), duk::optional<bool>(ctx, 1, false), 0);
 }
@@ -214,7 +214,7 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodRemove(duk::ContextPtr ctx)
+duk::Ret methodRemove(duk::Context *ctx)
 {
 	return remove(ctx, path(ctx), duk::optional<bool>(ctx, 0, false));
 }
@@ -240,7 +240,7 @@
  * Throws:
  *   - Any exception on error
  */
-duk::Ret constructor(duk::ContextPtr ctx)
+duk::Ret constructor(duk::Context *ctx)
 {
 	if (!duk_is_constructor_call(ctx))
 		return 0;
@@ -292,7 +292,7 @@
  * Returns:
  *   The path to the file or undefined on errors or not found.
  */
-duk::Ret funcFind(duk::ContextPtr ctx)
+duk::Ret funcFind(duk::Context *ctx)
 {
 	return find(ctx, duk::require<std::string>(ctx, 0), duk::optional<bool>(ctx, 2, false), 1);
 }
@@ -309,7 +309,7 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret funcRemove(duk::ContextPtr ctx)
+duk::Ret funcRemove(duk::Context *ctx)
 {
 	return remove(ctx, duk::require<std::string>(ctx, 0), duk::optional<bool>(ctx, 1, false));
 }
@@ -327,7 +327,7 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret funcMkdir(duk::ContextPtr ctx)
+duk::Ret funcMkdir(duk::Context *ctx)
 {
 	try {
 		fs::mkdir(duk::require<std::string>(ctx, 0), duk::optional<int>(ctx, 1, 0700));
@@ -366,11 +366,11 @@
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Function{constructor, 2});
-	duk::push(plugin.context(), constants);
-	duk::push(plugin.context(), functions);
+	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::push(plugin.context(), methods);
+	duk::put(plugin.context(), methods);
 	duk::putProperty(plugin.context(), -2, "prototype");
 	duk::putProperty(plugin.context(), -2, "Directory");
 	duk::pop(plugin.context());
--- a/lib/irccd/mod-elapsed-timer.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-elapsed-timer.cpp	Tue May 31 21:03:01 2016 +0200
@@ -22,19 +22,34 @@
 
 namespace irccd {
 
+namespace {
+
+const std::string Signature{"\xff""\xff""irccd-elapsed-timer-ptr"};
+
+} // !namespace
+
 namespace duk {
 
 template <>
-class TypeTraits<ElapsedTimer> {
+class TypeTraits<ElapsedTimer *> {
 public:
-	static inline std::string name()
+	static inline void construct(duk::Context *ctx, ElapsedTimer *timer)
 	{
-		return "\xff""\xff""ElapsedTimer";
+		duk::StackAssert sa(ctx);
+
+		duk::push(ctx, duk::This());
+		duk::putProperty<void *>(ctx, -1, Signature, timer);
+		duk::pop(ctx);
 	}
 
-	static inline std::vector<std::string> inherits()
+	static inline ElapsedTimer *require(duk::Context *ctx, Index index)
 	{
-		return {};
+		auto ptr = static_cast<ElapsedTimer *>(duk::getProperty<void *>(ctx, index, Signature));
+
+		if (!ptr)
+			duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object");
+
+		return ptr;
 	}
 };
 
@@ -48,9 +63,9 @@
  *
  * Pause the timer, without resetting the current elapsed time stored.
  */
-duk::Ret pause(duk::ContextPtr ctx)
+duk::Ret pause(duk::Context *ctx)
 {
-	duk::self<duk::Pointer<ElapsedTimer>>(ctx)->pause();
+	duk::self<ElapsedTimer *>(ctx)->pause();
 
 	return 0;
 }
@@ -61,9 +76,9 @@
  *
  * Reset the elapsed time to 0, the status is not modified.
  */
-duk::Ret reset(duk::ContextPtr ctx)
+duk::Ret reset(duk::Context *ctx)
 {
-	duk::self<duk::Pointer<ElapsedTimer>>(ctx)->reset();
+	duk::self<ElapsedTimer *>(ctx)->reset();
 
 	return 0;
 }
@@ -74,9 +89,9 @@
  *
  * Restart the timer without resetting the current elapsed time.
  */
-duk::Ret restart(duk::ContextPtr ctx)
+duk::Ret restart(duk::Context *ctx)
 {
-	duk::self<duk::Pointer<ElapsedTimer>>(ctx)->restart();
+	duk::self<ElapsedTimer *>(ctx)->restart();
 
 	return 0;
 }
@@ -90,9 +105,9 @@
  * Returns:
  *   The time elapsed.
  */
-duk::Ret elapsed(duk::ContextPtr ctx)
+duk::Ret elapsed(duk::Context *ctx)
 {
-	duk::push(ctx, (int)duk::self<duk::Pointer<ElapsedTimer>>(ctx)->elapsed());
+	duk::push(ctx, static_cast<int>(duk::self<ElapsedTimer *>(ctx)->elapsed()));
 
 	return 1;
 }
@@ -103,9 +118,24 @@
  *
  * Construct a new ElapsedTimer object.
  */
-duk::Ret constructor(duk::ContextPtr ctx)
+duk::Ret constructor(duk::Context *ctx)
 {
-	duk::construct(ctx, duk::Pointer<ElapsedTimer>{new ElapsedTimer});
+	duk::construct(ctx, new ElapsedTimer);
+
+	return 0;
+}
+
+/*
+ * Function: Irccd.ElapsedTimer() [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+duk::Ret destructor(duk::Context *ctx)
+{
+	delete static_cast<ElapsedTimer *>(duk::getProperty<void *>(ctx, 0, Signature));
+
+	duk::deleteProperty(ctx, 0, Signature);
 
 	return 0;
 }
@@ -131,7 +161,9 @@
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Function{constructor, 0});
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), methods);
+	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());
--- a/lib/irccd/mod-elapsed-timer.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-elapsed-timer.hpp	Tue May 31 21:03:01 2016 +0200
@@ -41,7 +41,7 @@
 	/**
 	 * \copydoc Module::load
 	 */
-	IRCCD_EXPORT virtual void load(Irccd &irccd, JsPlugin &plugin);
+	IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override;
 };
 
 } // !irccd
--- a/lib/irccd/mod-file.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-file.cpp	Tue May 31 21:03:01 2016 +0200
@@ -18,6 +18,7 @@
 
 #include <algorithm>
 #include <array>
+#include <cassert>
 #include <iterator>
 #include <vector>
 
@@ -35,6 +36,13 @@
 
 namespace irccd {
 
+namespace {
+
+const std::string Signature("\xff""\xff""irccd-file-ptr");
+const std::string Prototype("\xff""\xff""irccd-file-prototype");
+
+} // !namespace
+
 #if defined(HAVE_STAT)
 
 /*
@@ -47,7 +55,7 @@
 template <>
 class TypeTraits<struct stat> {
 public:
-	static void push(ContextPtr ctx, const struct stat &st)
+	static void push(Context *ctx, const struct stat &st)
 	{
 		duk::push(ctx, Object{});
 
@@ -104,7 +112,7 @@
  * ------------------------------------------------------------------
  */
 
-/* Remove trailing \r for CRLF line style */
+// Remove trailing \r for CRLF line style.
 inline std::string clearCr(std::string input)
 {
 	if (input.length() > 0 && input.back() == '\r')
@@ -127,9 +135,9 @@
  * Returns:
  *   The base name.
  */
-duk::Ret methodBasename(duk::ContextPtr ctx)
+duk::Ret methodBasename(duk::Context *ctx)
 {
-	duk::push(ctx, fs::baseName(duk::self<duk::Pointer<File>>(ctx)->path()));
+	duk::push(ctx, fs::baseName(duk::self<File *>(ctx)->path()));
 
 	return 1;
 }
@@ -140,9 +148,9 @@
  *
  * Force close of the file, automatically called when object is collected.
  */
-duk::Ret methodClose(duk::ContextPtr ctx)
+duk::Ret methodClose(duk::Context *ctx)
 {
-	duk::self<duk::Pointer<File>>(ctx)->close();
+	duk::self<File *>(ctx)->close();
 
 	return 0;
 }
@@ -156,9 +164,9 @@
  * Returns:
  *   The directory name.
  */
-duk::Ret methodDirname(duk::ContextPtr ctx)
+duk::Ret methodDirname(duk::Context *ctx)
 {
-	duk::push(ctx, fs::dirName(duk::self<duk::Pointer<File>>(ctx)->path()));
+	duk::push(ctx, fs::dirName(duk::self<File *>(ctx)->path()));
 
 	return 1;
 }
@@ -174,11 +182,11 @@
  * Throws
  *   - Any exception on error.
  */
-duk::Ret methodLines(duk::ContextPtr ctx)
+duk::Ret methodLines(duk::Context *ctx)
 {
 	duk::push(ctx, duk::Array{});
 
-	std::FILE *fp = duk::self<duk::Pointer<File>>(ctx)->handle();
+	std::FILE *fp = duk::self<File *>(ctx)->handle();
 	std::string buffer;
 	std::array<char, 128> data;
 	std::int32_t i = 0;
@@ -218,10 +226,10 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodRead(duk::ContextPtr ctx)
+duk::Ret methodRead(duk::Context *ctx)
 {
 	auto amount = duk::optional<int>(ctx, 0, -1);
-	auto file = duk::self<duk::Pointer<File>>(ctx);
+	auto file = duk::self<File *>(ctx);
 
 	if (amount == 0 || file->handle() == nullptr)
 		return 0;
@@ -272,9 +280,9 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodReadline(duk::ContextPtr ctx)
+duk::Ret methodReadline(duk::Context *ctx)
 {
-	std::FILE *fp = duk::self<duk::Pointer<File>>(ctx)->handle();
+	std::FILE *fp = duk::self<File *>(ctx)->handle();
 	std::string result;
 
 	if (fp == nullptr || std::feof(fp))
@@ -298,9 +306,9 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodRemove(duk::ContextPtr ctx)
+duk::Ret methodRemove(duk::Context *ctx)
 {
-	if (::remove(duk::self<duk::Pointer<File>>(ctx)->path().c_str()) < 0)
+	if (::remove(duk::self<File *>(ctx)->path().c_str()) < 0)
 		duk::raise(ctx, SystemError());
 
 	return 0;
@@ -318,11 +326,11 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodSeek(duk::ContextPtr ctx)
+duk::Ret methodSeek(duk::Context *ctx)
 {
 	auto type = duk::require<int>(ctx, 0);
 	auto amount = duk::require<int>(ctx, 1);
-	auto fp = duk::self<duk::Pointer<File>>(ctx)->handle();
+	auto fp = duk::self<File *>(ctx)->handle();
 
 	if (fp != nullptr && std::fseek(fp, amount, type) != 0)
 		duk::raise(ctx, SystemError());
@@ -343,10 +351,10 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodStat(duk::ContextPtr ctx)
+duk::Ret methodStat(duk::Context *ctx)
 {
 	struct stat st;
-	auto file = duk::self<duk::Pointer<File>>(ctx);
+	auto file = duk::self<File *>(ctx);
 
 	if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0)
 		duk::raise(ctx, SystemError());
@@ -369,9 +377,9 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodTell(duk::ContextPtr ctx)
+duk::Ret methodTell(duk::Context *ctx)
 {
-	auto fp = duk::self<duk::Pointer<File>>(ctx)->handle();
+	auto fp = duk::self<File *>(ctx)->handle();
 	long pos;
 
 	if (fp == nullptr)
@@ -398,9 +406,9 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret methodWrite(duk::ContextPtr ctx)
+duk::Ret methodWrite(duk::Context *ctx)
 {
-	std::FILE *fp = duk::self<duk::Pointer<File>>(ctx)->handle();
+	std::FILE *fp = duk::self<File *>(ctx)->handle();
 	std::string data = duk::require<std::string>(ctx, 0);
 
 	if (fp == nullptr)
@@ -449,16 +457,13 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret constructor(duk::ContextPtr ctx)
+duk::Ret constructor(duk::Context *ctx)
 {
-	if (!duk_is_constructor_call(ctx))
+	if (!duk::isConstructorCall(ctx))
 		return 0;
 
-	std::string path = duk::require<std::string>(ctx, 0);
-	std::string mode = duk::require<std::string>(ctx, 1);
-
 	try {
-		duk::construct(ctx, duk::Pointer<File>{new File(path, mode)});
+		duk::construct(ctx, new File(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)));
 	} catch (const std::exception &) {
 		duk::raise(ctx, SystemError());
 	}
@@ -467,6 +472,21 @@
 }
 
 /*
+ * Function: Irccd.File() [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+duk::Ret destructor(duk::Context *ctx)
+{
+	delete static_cast<File *>(duk::getProperty<void *>(ctx, 0, Signature));
+
+	duk::deleteProperty(ctx, 0, Signature);
+
+	return 0;
+}
+
+/*
  * Function: Irccd.File.basename(path)
  * --------------------------------------------------------
  *
@@ -477,7 +497,7 @@
  * Returns:
  *   The base name.
  */
-duk::Ret functionBasename(duk::ContextPtr ctx)
+duk::Ret functionBasename(duk::Context *ctx)
 {
 	duk::push(ctx, fs::baseName(duk::require<std::string>(ctx, 0)));
 
@@ -495,7 +515,7 @@
  * Returns:
  *   The directory name.
  */
-duk::Ret functionDirname(duk::ContextPtr ctx)
+duk::Ret functionDirname(duk::Context *ctx)
 {
 	duk::push(ctx, fs::dirName( duk::require<std::string>(ctx, 0)));
 
@@ -515,7 +535,7 @@
  * Throws:
  *   - Any exception if we don't have access.
  */
-duk::Ret functionExists(duk::ContextPtr ctx)
+duk::Ret functionExists(duk::Context *ctx)
 {
 	duk::push(ctx, fs::exists(duk::require<std::string>(ctx, 0)));
 
@@ -533,7 +553,7 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret functionRemove(duk::ContextPtr ctx)
+duk::Ret functionRemove(duk::Context *ctx)
 {
 	if (::remove(duk::require<std::string>(ctx, 0).c_str()) < 0)
 		duk::raise(ctx, SystemError());
@@ -556,7 +576,7 @@
  * Throws:
  *   - Any exception on error.
  */
-duk::Ret functionStat(duk::ContextPtr ctx)
+duk::Ret functionStat(duk::Context *ctx)
 {
 	struct stat st;
 
@@ -588,6 +608,41 @@
 
 } // !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<void *>(ctx, -1, Signature, 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<void *>(ctx, -1, Signature, 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")
 {
@@ -598,11 +653,15 @@
 	duk::StackAssert sa(plugin.context());
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function{constructor, 2});
-	duk::push(plugin.context(), constants);
-	duk::push(plugin.context(), functions);
+	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::push(plugin.context(), methods);
+	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());
--- a/lib/irccd/mod-file.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-file.hpp	Tue May 31 21:03:01 2016 +0200
@@ -142,41 +142,33 @@
  * \brief JavaScript binding for File.
  */
 template <>
-class TypeTraits<File> {
+class TypeTraits<File *> {
 public:
 	/**
-	 * Push the File prototype.
+	 * Construct the file.
 	 *
-	 * \param ctx the context
+	 * \pre fp != nullptr
+	 * \param ctx the the context
+	 * \param fp the file
 	 */
-	static inline void prototype(ContextPtr ctx)
-	{
-		getGlobal<void>(ctx, "Irccd");
-		getGlobal<void>(ctx, "File");
-		getProperty<void>(ctx, -1, "prototype");
-		remove(ctx, -2);
-		remove(ctx, -2);
-	}
+	IRCCD_EXPORT static void construct(duk::Context *ctx, File *fp);
 
 	/**
-	 * Get the File signature.
+	 * Push a file.
 	 *
-	 * \return File
+	 * \pre fp != nullptr
+	 * \param ctx the the context
+	 * \param fp the file
 	 */
-	static inline std::string name()
-	{
-		return "\xff""\xff""File";
-	}
+	IRCCD_EXPORT static void push(duk::Context *ctx, File *fp);
 
 	/**
-	 * Get the inheritance list.
+	 * Require a file. Raises a JavaScript error if not a File.
 	 *
-	 * \return empty
+	 * \param ctx the context
+	 * \param index the index
 	 */
-	static inline std::vector<std::string> inherits()
-	{
-		return {};
-	}
+	IRCCD_EXPORT static File *require(duk::Context *ctx, Index index);
 };
 
 } // !duk
--- a/lib/irccd/mod-irccd.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-irccd.cpp	Tue May 31 21:03:01 2016 +0200
@@ -34,7 +34,7 @@
 {
 }
 
-void SystemError::raise(duk::ContextPtr ctx) const
+void SystemError::raise(duk::Context *ctx) const
 {
 	duk::StackAssert sa(ctx, 0);
 
@@ -47,7 +47,7 @@
 	duk::raise(ctx);
 }
 
-duk::Ret constructor(duk::ContextPtr ctx)
+duk::Ret constructor(duk::Context *ctx)
 {
 	duk::push(ctx, duk::This{});
 	duk::putProperty(ctx, -1, "errno", duk::require<int>(ctx, 0));
@@ -91,7 +91,7 @@
 	duk::putGlobal(plugin.context(), "Irccd");
 
 	// Store global instance.
-	duk::putGlobal(plugin.context(), "\xff""\xff""irccd", duk::RawPointer<Irccd>{&irccd});
+	duk::putGlobal(plugin.context(), "\xff""\xff""irccd",&irccd);
 }
 
 } // !irccd
--- a/lib/irccd/mod-irccd.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-irccd.hpp	Tue May 31 21:03:01 2016 +0200
@@ -62,7 +62,7 @@
 	 *
 	 * \param ctx the context
 	 */
-	IRCCD_EXPORT void raise(duk::ContextPtr ctx) const;
+	IRCCD_EXPORT void raise(duk::Context *ctx) const;
 };
 
 /**
--- a/lib/irccd/mod-logger.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-logger.cpp	Tue May 31 21:03:01 2016 +0200
@@ -24,7 +24,7 @@
 
 namespace {
 
-duk::Ret print(duk::ContextPtr ctx, std::ostream &out)
+duk::Ret print(duk::Context *ctx, std::ostream &out)
 {
 	/*
 	 * Get the message before we start printing stuff to avoid
@@ -45,7 +45,7 @@
  * Arguments:
  *   - message, the message.
  */
-duk::Ret info(duk::ContextPtr ctx)
+duk::Ret info(duk::Context *ctx)
 {
 	return print(ctx, log::info());
 }
@@ -59,7 +59,7 @@
  * Arguments:
  *   - message, the warning.
  */
-duk::Ret warning(duk::ContextPtr ctx)
+duk::Ret warning(duk::Context *ctx)
 {
 	return print(ctx, log::warning());
 }
@@ -73,7 +73,7 @@
  * Arguments:
  *   - message, the message.
  */
-duk::Ret debug(duk::ContextPtr ctx)
+duk::Ret debug(duk::Context *ctx)
 {
 	return print(ctx, log::debug());
 }
@@ -97,7 +97,7 @@
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), functions);
+	duk::put(plugin.context(), functions);
 	duk::putProperty(plugin.context(), -2, "Logger");
 	duk::pop(plugin.context());
 }
--- a/lib/irccd/mod-plugin.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-plugin.cpp	Tue May 31 21:03:01 2016 +0200
@@ -25,6 +25,8 @@
 
 namespace {
 
+const std::string PluginGlobal{"\xff""\xff""irccd-plugin-ptr"};
+
 /*
  * Wrap function for these functions because they all takes the same arguments.
  *
@@ -33,12 +35,12 @@
  * - unload.
  */
 template <typename Func>
-duk::Ret wrap(duk::ContextPtr ctx, int nret, Func &&func)
+duk::Ret wrap(duk::Context *ctx, int nret, Func &&func)
 {
 	std::string name = duk::require<std::string>(ctx, 0);
 
 	try {
-		func(*duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd"), name);
+		func(*duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd"), name);
 	} catch (const std::out_of_range &ex) {
 		duk::raise(ctx, duk::ReferenceError(ex.what()));
 	} catch (const std::exception &ex) {
@@ -67,14 +69,14 @@
  * Returns:
  *   The plugin information or undefined if the plugin was not found.
  */
-duk::Ret info(duk::ContextPtr ctx)
+duk::Ret info(duk::Context *ctx)
 {
 	Plugin *plugin = nullptr;
 
 	if (duk::top(ctx) >= 1)
-		plugin = duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->pluginService().get(duk::require<std::string>(ctx, 0)).get();
+		plugin = duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->pluginService().get(duk::require<std::string>(ctx, 0)).get();
 	else
-		plugin = duk::getGlobal<duk::RawPointer<Plugin>>(ctx, "\xff""\xff""plugin");
+		plugin = duk::getGlobal<Plugin *>(ctx, "\xff""\xff""plugin");
 
 	if (!plugin)
 		return 0;
@@ -98,12 +100,12 @@
  * Returns:
  *   The list of all plugin names.
  */
-duk::Ret list(duk::ContextPtr ctx)
+duk::Ret list(duk::Context *ctx)
 {
 	duk::push(ctx, duk::Array{});
 
 	int i = 0;
-	for (const auto &plugin : duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->pluginService().plugins())
+	for (const auto &plugin : duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->pluginService().plugins())
 		duk::putProperty(ctx, -1, i++, plugin->name());
 
 	return 1;
@@ -121,7 +123,7 @@
  *   - Error on errors,
  *   - ReferenceError if the plugin was not found.
  */
-duk::Ret load(duk::ContextPtr ctx)
+duk::Ret load(duk::Context *ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
 		irccd.pluginService().load(name);
@@ -140,7 +142,7 @@
  *   - Error on errors,
  *   - ReferenceError if the plugin was not found.
  */
-duk::Ret reload(duk::ContextPtr ctx)
+duk::Ret reload(duk::Context *ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
 		irccd.pluginService().reload(name);
@@ -159,7 +161,7 @@
  *   - Error on errors,
  *   - ReferenceError if the plugin was not found.
  */
-duk::Ret unload(duk::ContextPtr ctx)
+duk::Ret unload(duk::Context *ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
 		irccd.pluginService().unload(name);
@@ -176,6 +178,15 @@
 
 } // !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")
 {
@@ -185,9 +196,10 @@
 {
 	duk::StackAssert sa(plugin.context());
 
+	duk::putGlobal<void *>(plugin.context(), PluginGlobal, &plugin);
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), functions);
+	duk::put(plugin.context(), functions);
 	duk::push(plugin.context(), duk::Object{});
 	duk::putProperty(plugin.context(), -2, "config");
 	duk::push(plugin.context(), duk::Object{});
--- a/lib/irccd/mod-plugin.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-plugin.hpp	Tue May 31 21:03:01 2016 +0200
@@ -24,10 +24,31 @@
  * \brief Irccd.Plugin JavaScript API.
  */
 
+#include "js.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.
  */
@@ -41,7 +62,7 @@
 	/**
 	 * \copydoc Module::load
 	 */
-	IRCCD_EXPORT virtual void load(Irccd &irccd, JsPlugin &plugin);
+	IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override;
 };
 
 } // !irccd
--- a/lib/irccd/mod-server.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-server.cpp	Tue May 31 21:03:01 2016 +0200
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <cassert>
 #include <sstream>
 #include <unordered_map>
 
@@ -29,6 +30,9 @@
 
 namespace {
 
+const std::string Signature("\xff""\xff""irccd-server-ptr");
+const std::string Prototype("\xff""\xff""irccd-server-prototype");
+
 /*
  * Method: Server.cmode(channel, mode)
  * ------------------------------------------------------------------
@@ -39,9 +43,9 @@
  *   - channel, the channel,
  *   - mode, the mode.
  */
-duk::Ret cmode(duk::ContextPtr ctx)
+duk::Ret cmode(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->cmode(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->cmode(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -56,9 +60,9 @@
  *   - channel, the channel,
  *   - message, the message.
  */
-duk::Ret cnotice(duk::ContextPtr ctx)
+duk::Ret cnotice(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->cnotice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->cnotice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -76,9 +80,9 @@
  * sslVerify: true if ssl was verified
  * channels: an array of all channels
  */
-duk::Ret info(duk::ContextPtr ctx)
+duk::Ret info(duk::Context *ctx)
 {
-	auto server = duk::self<duk::Shared<Server>>(ctx);
+	auto server = duk::self<std::shared_ptr<Server>>(ctx);
 
 	duk::push(ctx, duk::Object{});
 	duk::putProperty(ctx, -1, "name", server->name());
@@ -113,9 +117,9 @@
  *   - target, the target to invite,
  *   - channel, the channel.
  */
-duk::Ret invite(duk::ContextPtr ctx)
+duk::Ret invite(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->invite(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->invite(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -130,9 +134,9 @@
  *   - channel, the channel to join,
  *   - password, the password or undefined to not use.
  */
-duk::Ret join(duk::ContextPtr ctx)
+duk::Ret join(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->join(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, ""));
+	duk::self<std::shared_ptr<Server>>(ctx)->join(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, ""));
 
 	return 0;
 }
@@ -148,9 +152,9 @@
  *   - channel, the channel,
  *   - reason, the optional reason or undefined to not set.
  */
-duk::Ret kick(duk::ContextPtr ctx)
+duk::Ret kick(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->kick(
+	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, "")
@@ -169,9 +173,9 @@
  *   - target, the target or a channel,
  *   - message, the message.
  */
-duk::Ret me(duk::ContextPtr ctx)
+duk::Ret me(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->me(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->me(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -186,9 +190,9 @@
  *   - target, the target or a channel,
  *   - message, the message.
  */
-duk::Ret message(duk::ContextPtr ctx)
+duk::Ret message(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->message(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->message(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -202,9 +206,9 @@
  * Arguments:
  *   - mode, the new mode.
  */
-duk::Ret mode(duk::ContextPtr ctx)
+duk::Ret mode(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->mode(duk::require<std::string>(ctx, 0));
+	duk::self<std::shared_ptr<Server>>(ctx)->mode(duk::require<std::string>(ctx, 0));
 
 	return 0;
 }
@@ -218,9 +222,9 @@
  * Arguments:
  *   - channel, the channel.
  */
-duk::Ret names(duk::ContextPtr ctx)
+duk::Ret names(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->names(duk::require<std::string>(ctx, 0));
+	duk::self<std::shared_ptr<Server>>(ctx)->names(duk::require<std::string>(ctx, 0));
 
 	return 0;
 }
@@ -234,9 +238,9 @@
  * Arguments:
  *   - nickname, the nickname.
  */
-duk::Ret nick(duk::ContextPtr ctx)
+duk::Ret nick(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->nick(duk::require<std::string>(ctx, 0));
+	duk::self<std::shared_ptr<Server>>(ctx)->nick(duk::require<std::string>(ctx, 0));
 
 	return 0;
 }
@@ -251,9 +255,9 @@
  *   - target, the target,
  *   - message, the notice message.
  */
-duk::Ret notice(duk::ContextPtr ctx)
+duk::Ret notice(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->notice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->notice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -268,9 +272,9 @@
  *   - channel, the channel to leave,
  *   - reason, the optional reason, keep undefined for portability.
  */
-duk::Ret part(duk::ContextPtr ctx)
+duk::Ret part(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->part(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, ""));
+	duk::self<std::shared_ptr<Server>>(ctx)->part(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, ""));
 
 	return 0;
 }
@@ -284,9 +288,9 @@
  * Arguments:
  *   - raw, the raw message (without terminators).
  */
-duk::Ret send(duk::ContextPtr ctx)
+duk::Ret send(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->send(duk::require<std::string>(ctx, 0));
+	duk::self<std::shared_ptr<Server>>(ctx)->send(duk::require<std::string>(ctx, 0));
 
 	return 0;
 }
@@ -301,9 +305,9 @@
  *   - channel, the channel,
  *   - topic, the new topic.
  */
-duk::Ret topic(duk::ContextPtr ctx)
+duk::Ret topic(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->topic(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
+	duk::self<std::shared_ptr<Server>>(ctx)->topic(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1));
 
 	return 0;
 }
@@ -317,9 +321,9 @@
  * Arguments:
  *   - target, the target.
  */
-duk::Ret whois(duk::ContextPtr ctx)
+duk::Ret whois(duk::Context *ctx)
 {
-	duk::self<duk::Shared<Server>>(ctx)->whois(duk::require<std::string>(ctx, 0));
+	duk::self<std::shared_ptr<Server>>(ctx)->whois(duk::require<std::string>(ctx, 0));
 
 	return 0;
 }
@@ -334,9 +338,9 @@
  * Returns:
  *   The server name (unique).
  */
-duk::Ret toString(duk::ContextPtr ctx)
+duk::Ret toString(duk::Context *ctx)
 {
-	duk::push(ctx, duk::self<duk::Shared<Server>>(ctx)->name());
+	duk::push(ctx, duk::self<std::shared_ptr<Server>>(ctx)->name());
 
 	return 1;
 }
@@ -362,9 +366,9 @@
  * realname: "real name",	(Optional, default: IRC Client Daemon)
  * commandChar: "!",		(Optional, the command char, default: "!")
  */
-duk::Ret constructor(duk::ContextPtr ctx)
+duk::Ret constructor(duk::Context *ctx)
 {
-	if (!duk_is_constructor_call(ctx))
+	if (!duk::isConstructorCall(ctx))
 		return 0;
 
 	std::string name;
@@ -375,12 +379,11 @@
 	// 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", (int)info.port);
+	info.port = duk::optionalProperty<int>(ctx, 0, "port", static_cast<int>(info.port));
 	info.password = duk::optionalProperty<std::string>(ctx, 0, "password", "");
 
-	if (duk::optionalProperty<bool>(ctx, 0, "ipv6", false)) {
+	if (duk::optionalProperty<bool>(ctx, 0, "ipv6", false))
 		info.flags |= ServerInfo::Ipv6;
-	}
 
 	// Identity part.
 	identity.nickname = duk::optionalProperty<std::string>(ctx, 0, "nickname", identity.nickname);
@@ -401,8 +404,7 @@
 		settings.flags |= ServerSettings::AutoRejoin;
 
 	try {
-		duk::construct(ctx, duk::Shared<Server>{std::make_shared<Server>(std::move(name), std::move(info),
-							std::move(identity), std::move(settings))});
+		duk::construct(ctx, std::make_shared<Server>(std::move(name), std::move(info), std::move(identity), std::move(settings)));
 	} catch (const std::exception &ex) {
 		duk::raise(ctx, duk::Error(ex.what()));
 	}
@@ -411,6 +413,22 @@
 }
 
 /*
+ * Function: Irccd.Server() [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+duk::Ret destructor(duk::Context *ctx)
+{
+	delete static_cast<std::shared_ptr<Server> *>(duk::getProperty<void *>(ctx, 0, Signature));
+
+	duk::deleteProperty(ctx, 0, Signature);
+
+	return 0;
+}
+
+
+/*
  * Function: Irccd.Server.add(s)
  * ------------------------------------------------------------------
  *
@@ -419,12 +437,9 @@
  * Arguments:
  *   - s, the server to add.
  */
-duk::Ret add(duk::ContextPtr ctx)
+duk::Ret add(duk::Context *ctx)
 {
-	auto server = duk::get<duk::Shared<Server>>(ctx, 0);
-
-	if (server)
-		duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->serverService().add(server);
+	duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().add(duk::require<std::shared_ptr<Server>>(ctx, 0));
 
 	return 0;
 }
@@ -440,13 +455,13 @@
  * Returns:
  *   The server object or undefined if not found.
  */
-duk::Ret find(duk::ContextPtr ctx)
+duk::Ret find(duk::Context *ctx)
 {
 	const auto name = duk::require<std::string>(ctx, 0);
-	const auto irccd = duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd");
+	const auto irccd = duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd");
 
 	try {
-		duk::push(ctx, duk::Shared<Server>{irccd->serverService().require(name)});
+		duk::push(ctx, irccd->serverService().require(name));
 	} catch (...) {
 		return 0;
 	}
@@ -463,12 +478,12 @@
  * Returns:
  *   An object with string-to-servers pairs.
  */
-duk::Ret list(duk::ContextPtr ctx)
+duk::Ret list(duk::Context *ctx)
 {
 	duk::push(ctx, duk::Object{});
 
-	for (const auto &server : duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->serverService().servers())
-		duk::putProperty(ctx, -1, server->name(), duk::Shared<Server>{server});
+	for (const auto &server : duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().servers())
+		duk::putProperty(ctx, -1, server->name(), server);
 
 	return 1;
 }
@@ -482,9 +497,9 @@
  * Arguments:
  *   - name the server name.
  */
-duk::Ret remove(duk::ContextPtr ctx)
+duk::Ret remove(duk::Context *ctx)
 {
-	duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->serverService().remove(duk::require<std::string>(ctx, 0));
+	duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().remove(duk::require<std::string>(ctx, 0));
 
 	return 0;
 }
@@ -518,6 +533,43 @@
 
 } // !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")
 {
@@ -528,10 +580,14 @@
 	duk::StackAssert sa(plugin.context());
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
-	duk::push(plugin.context(), duk::Function{constructor, 1});
-	duk::push(plugin.context(), functions);
+	duk::push(plugin.context(), duk::Function(constructor, 1));
+	duk::put(plugin.context(), functions);
 	duk::push(plugin.context(), duk::Object());
-	duk::push(plugin.context(), methods);
+	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());
--- a/lib/irccd/mod-server.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-server.hpp	Tue May 31 21:03:01 2016 +0200
@@ -36,41 +36,34 @@
  * \brief JavaScript binding for Server.
  */
 template <>
-class TypeTraits<irccd::Server> {
+class TypeTraits<std::shared_ptr<Server>> {
 public:
 	/**
-	 * Push the Server prototype.
+	 * Construct a server.
 	 *
+	 * \pre server != nullptr
 	 * \param ctx the context
+	 * \param server the server
 	 */
-	static inline void prototype(ContextPtr ctx)
-	{
-		getGlobal<void>(ctx, "Irccd");
-		getProperty<void>(ctx, -1, "Server");
-		getProperty<void>(ctx, -1, "prototype");
-		remove(ctx, -2);
-		remove(ctx, -2);
-	}
+	IRCCD_EXPORT static void construct(Context *ctx, std::shared_ptr<Server> server);
 
 	/**
-	 * Get the Server signature.
+	 * Push a server.
 	 *
-	 * \return Server
+	 * \pre server != nullptr
+	 * \param ctx the context
+	 * \param server the server
 	 */
-	static inline std::string name()
-	{
-		return "\xff""\xff""Server";
-	}
+	IRCCD_EXPORT static void push(Context *ctx, std::shared_ptr<Server>);
 
 	/**
-	 * Get the inheritance list.
+	 * Require a server. Raise a JavaScript error if not a Server.
 	 *
-	 * \return empty
+	 * \param ctx the context
+	 * \param index the index
+	 * \return the server
 	 */
-	static inline std::vector<std::string> inherits()
-	{
-		return {};
-	}
+	IRCCD_EXPORT static std::shared_ptr<Server> require(Context *ctx, Index index);
 };
 
 } // !duk
--- a/lib/irccd/mod-system.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-system.cpp	Tue May 31 21:03:01 2016 +0200
@@ -47,7 +47,7 @@
  * Returns:
  *   The value.
  */
-int env(duk::ContextPtr ctx)
+int env(duk::Context *ctx)
 {
 	duk::push(ctx, sys::env(duk::get<std::string>(ctx, 0)));
 
@@ -63,7 +63,7 @@
  * Arguments:
  *   - cmd, the command to execute.
  */
-int exec(duk::ContextPtr ctx)
+int exec(duk::Context *ctx)
 {
 	std::system(duk::get<const char *>(ctx, 0));
 
@@ -79,7 +79,7 @@
  * Returns:
  *   The user home directory.
  */
-int home(duk::ContextPtr ctx)
+int home(duk::Context *ctx)
 {
 	duk::push(ctx, sys::home());
 
@@ -95,7 +95,7 @@
  * Returns:
  *   The system name.
  */
-int name(duk::ContextPtr ctx)
+int name(duk::Context *ctx)
 {
 	duk::push(ctx, sys::name());
 
@@ -118,14 +118,14 @@
  * Throws
  *   - Irccd.SystemError on failures.
  */
-int popen(duk::ContextPtr ctx)
+int popen(duk::Context *ctx)
 {
 	auto fp = ::popen(duk::require<const char *>(ctx, 0), duk::require<const char *>(ctx, 1));
 
 	if (fp == nullptr)
 		duk::raise(ctx, SystemError{});
 
-	duk::push(ctx, duk::Pointer<File>{new File(fp, [] (std::FILE *fp) { ::pclose(fp); })});
+	duk::push(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); }));
 
 	return 1;
 }
@@ -138,7 +138,7 @@
  *
  * Sleep the main loop for the specific delay in seconds.
  */
-int sleep(duk::ContextPtr ctx)
+int sleep(duk::Context *ctx)
 {
 	std::this_thread::sleep_for(std::chrono::seconds(duk::get<int>(ctx, 0)));
 
@@ -154,7 +154,7 @@
  * Returns:
  *   The number of milliseconds.
  */
-int ticks(duk::ContextPtr ctx)
+int ticks(duk::Context *ctx)
 {
 	duk::push(ctx, static_cast<int>(sys::ticks()));
 
@@ -167,7 +167,7 @@
  *
  * Sleep the main loop for the specific delay in microseconds.
  */
-int usleep(duk::ContextPtr ctx)
+int usleep(duk::Context *ctx)
 {
 	std::this_thread::sleep_for(std::chrono::microseconds(duk::get<int>(ctx, 0)));
 
@@ -183,7 +183,7 @@
  * Returns:
  *   The system uptime.
  */
-int uptime(duk::ContextPtr ctx)
+int uptime(duk::Context *ctx)
 {
 	duk::push<int>(ctx, sys::uptime());
 
@@ -199,7 +199,7 @@
  * Returns:
  *   The system version.
  */
-int version(duk::ContextPtr ctx)
+int version(duk::Context *ctx)
 {
 	duk::push(ctx, sys::version());
 
@@ -234,7 +234,7 @@
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), functions);
+	duk::put(plugin.context(), functions);
 	duk::putProperty(plugin.context(), -2, "System");
 	duk::pop(plugin.context());
 }
--- a/lib/irccd/mod-timer.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-timer.cpp	Tue May 31 21:03:01 2016 +0200
@@ -21,6 +21,7 @@
 #include "irccd.hpp"
 #include "logger.hpp"
 #include "mod-timer.hpp"
+#include "mod-plugin.hpp"
 #include "plugin-js.hpp"
 #include "timer.hpp"
 
@@ -28,19 +29,35 @@
 
 namespace irccd {
 
+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<Timer> {
+class TypeTraits<std::shared_ptr<Timer>> {
 public:
-	static std::string name() noexcept
+	static inline void construct(duk::Context *ctx, std::shared_ptr<Timer> timer)
 	{
-		return "\xff""\xff""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 std::vector<std::string> inherits()
+	static inline std::shared_ptr<Timer> require(duk::Context *ctx, duk::Index index)
 	{
-		return {};
+		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;
 	}
 };
 
@@ -48,8 +65,6 @@
 
 namespace {
 
-const std::string CallbackTable{"\xff""\xff""irccd-timer-callbacks"};
-
 void handleSignal(std::weak_ptr<JsPlugin> ptr, std::string key)
 {
 	auto plugin = ptr.lock();
@@ -57,7 +72,7 @@
 	if (!plugin)
 		return;
 
-	auto irccd = duk::getGlobal<duk::RawPointer<Irccd>>(plugin->context(), "\xff""\xff""irccd");
+	auto irccd = duk::getGlobal<Irccd *>(plugin->context(), "\xff""\xff""irccd");
 
 	irccd->post([plugin, key] (Irccd &) {
 		duk::StackAssert sa(plugin->context());
@@ -68,9 +83,9 @@
 
 		if (duk::is<duk::Function>(plugin->context(), -1)) {
 			if (duk::pcall(plugin->context()) != 0)
-				log::warning("plugin {}: {}"_format(plugin->name(), duk::error(plugin->context(), -1).stack));
-
-			duk::pop(plugin->context());
+				log::warning("plugin {}: {}"_format(plugin->name(), duk::exception(plugin->context(), -1).stack));
+			else
+				duk::pop(plugin->context());
 		} else
 			duk::pop(plugin->context());
 	});
@@ -82,9 +97,9 @@
  *
  * Start the timer. If the timer is already started the method is a no-op.
  */
-duk::Ret start(duk::ContextPtr ctx)
+duk::Ret start(duk::Context *ctx)
 {
-	auto timer = duk::self<duk::Shared<Timer>>(ctx);
+	auto timer = duk::self<std::shared_ptr<Timer>>(ctx);
 
 	if (!timer->isRunning())
 		timer->start();
@@ -98,9 +113,9 @@
  *
  * Stop the timer.
  */
-duk::Ret stop(duk::ContextPtr ctx)
+duk::Ret stop(duk::Context *ctx)
 {
-	auto timer = duk::self<duk::Shared<Timer>>(ctx);
+	auto timer = duk::self<std::shared_ptr<Timer>>(ctx);
 
 	if (timer->isRunning())
 		timer->stop();
@@ -124,7 +139,7 @@
  *   - delay, the interval in milliseconds,
  *   - callback, the function to call.
  */
-duk::Ret constructor(duk::ContextPtr ctx)
+duk::Ret constructor(duk::Context *ctx)
 {
 	// Check parameters.
 	auto type = duk::require<int>(ctx, 0);
@@ -139,19 +154,20 @@
 
 	// Construct the timer in 'this'.
 	auto timer = std::make_shared<Timer>(static_cast<TimerType>(type), delay);
-	auto plugin = std::static_pointer_cast<JsPlugin>(duk::getGlobal<duk::RawPointer<Plugin>>(ctx, "\xff""\xff""plugin")->shared_from_this());
+	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));
 
 	// Set a finalizer that closes the timer.
-	duk::construct(ctx, duk::Shared<Timer>{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::ContextPtr ctx) -> duk::Ret {
+	duk::push(ctx, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
 		duk::StackAssert sa(ctx);
 
-		duk::get<duk::Shared<Timer>>(ctx, 0)->stop();
+		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);
@@ -188,9 +204,9 @@
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Function{constructor, 3});
-	duk::push(plugin.context(), constants);
+	duk::put(plugin.context(), constants);
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), methods);
+	duk::put(plugin.context(), methods);
 	duk::putProperty(plugin.context(), -2, "prototype");
 	duk::putProperty(plugin.context(), -2, "Timer");
 	duk::pop(plugin.context());
--- a/lib/irccd/mod-unicode.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-unicode.cpp	Tue May 31 21:03:01 2016 +0200
@@ -34,7 +34,7 @@
  * Returns:
  *   True if the code is in the digit category.
  */
-duk::Ret isDigit(duk::ContextPtr ctx)
+duk::Ret isDigit(duk::Context *ctx)
 {
 	duk::push(ctx, unicode::isdigit(duk::get<int>(ctx, 0)));
 
@@ -50,7 +50,7 @@
  * Returns:
  *   True if the code is in the letter category.
  */
-duk::Ret isLetter(duk::ContextPtr ctx)
+duk::Ret isLetter(duk::Context *ctx)
 {
 	duk::push(ctx, unicode::isalpha(duk::get<int>(ctx, 0)));
 
@@ -66,7 +66,7 @@
  * Returns:
  *   True if the code is lower case.
  */
-duk::Ret isLower(duk::ContextPtr ctx)
+duk::Ret isLower(duk::Context *ctx)
 {
 	duk::push(ctx, unicode::islower(duk::get<int>(ctx, 0)));
 
@@ -82,7 +82,7 @@
  * Returns:
  *   True if the code is in the space category.
  */
-duk::Ret isSpace(duk::ContextPtr ctx)
+duk::Ret isSpace(duk::Context *ctx)
 {
 	duk::push(ctx, unicode::isspace(duk::get<int>(ctx, 0)));
 
@@ -98,7 +98,7 @@
  * Returns:
  *   True if the code is title case.
  */
-duk::Ret isTitle(duk::ContextPtr ctx)
+duk::Ret isTitle(duk::Context *ctx)
 {
 	duk::push(ctx, unicode::istitle(duk::get<int>(ctx, 0)));
 
@@ -114,7 +114,7 @@
  * Returns:
  *   True if the code is upper case.
  */
-duk::Ret isUpper(duk::ContextPtr ctx)
+duk::Ret isUpper(duk::Context *ctx)
 {
 	duk::push(ctx, unicode::isupper(duk::get<int>(ctx, 0)));
 
@@ -143,7 +143,7 @@
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), functions);
+	duk::put(plugin.context(), functions);
 	duk::putProperty(plugin.context(), -2, "Unicode");
 	duk::pop(plugin.context());
 }
--- a/lib/irccd/mod-util.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/mod-util.cpp	Tue May 31 21:03:01 2016 +0200
@@ -40,20 +40,18 @@
 template <>
 class TypeTraits<util::Substitution> {
 public:
-	static util::Substitution get(ContextPtr ctx, int index)
+	static util::Substitution get(duk::Context *ctx, int index)
 	{
 		util::Substitution params;
 
-		if (!duk::is<Object>(ctx, index)) {
+		if (!duk::is<Object>(ctx, index))
 			return params;
-		}
 
-		duk::enumerate(ctx, index, 0, true, [&] (ContextPtr) {
-			if (duk::get<std::string>(ctx, -2) == "date") {
+		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 {
+			else
 				params.keywords.insert({duk::get<std::string>(ctx, -2), duk::get<std::string>(ctx, -1)});
-			}
 		});
 
 		return params;
@@ -76,7 +74,7 @@
  * Returns:
  *   The converted text.
  */
-duk::Ret format(duk::ContextPtr ctx)
+duk::Ret format(duk::Context *ctx)
 {
 	try {
 		duk::push(ctx, util::format(duk::get<std::string>(ctx, 0), duk::get<util::Substitution>(ctx, 1)));
@@ -98,7 +96,7 @@
  * Returns:
  *   The nickname.
  */
-duk::Ret splituser(duk::ContextPtr ctx)
+duk::Ret splituser(duk::Context *ctx)
 {
 	const char *target = duk::require<const char *>(ctx, 0);
 	char nick[32] = {0};
@@ -120,7 +118,7 @@
  * Returns:
  *   The hostname.
  */
-duk::Ret splithost(duk::ContextPtr ctx)
+duk::Ret splithost(duk::Context *ctx)
 {
 	const char *target = duk::require<const char *>(ctx, 0);
 	char host[32] = {0};
@@ -150,7 +148,7 @@
 
 	duk::getGlobal<void>(plugin.context(), "Irccd");
 	duk::push(plugin.context(), duk::Object{});
-	duk::push(plugin.context(), functions);
+	duk::put(plugin.context(), functions);
 	duk::putProperty(plugin.context(), -2, "Util");
 	duk::pop(plugin.context());
 }
--- a/lib/irccd/plugin-js.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/plugin-js.cpp	Tue May 31 21:03:01 2016 +0200
@@ -45,14 +45,10 @@
 		// Call the function and discard the result.
 		duk::insert(m_context, -nargs - 1);
 
-		if (duk::pcall(m_context, nargs) != 0) {
-			auto error = duk::error(m_context, -1);
+		if (duk::pcall(m_context, nargs) != 0)
+			throw duk::exception(m_context, -1, true);
 
-			duk::pop(m_context);
-
-			throw error;
-		} else
-			duk::pop(m_context);
+		duk::pop(m_context);
 	}
 }
 
@@ -66,7 +62,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::putGlobal(m_context, "\xff""\xff""plugin", duk::RawPointer<JsPlugin>{this});
+	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());
 }
@@ -145,7 +141,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, mode);
@@ -161,7 +157,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, notice);
@@ -176,7 +172,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, message);
@@ -187,7 +183,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	call("onConnect", 1);
 }
 
@@ -195,7 +191,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	call("onInvite", 3);
@@ -205,7 +201,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	call("onJoin", 3);
@@ -220,7 +216,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, target);
@@ -256,7 +252,7 @@
 
 	// Try to load the file (does not call onLoad yet).
 	if (duk::pevalFile(m_context, path()) != 0)
-		throw duk::error(m_context, -1);
+		throw duk::exception(m_context, -1, true);
 
 	duk::pop(m_context);
 
@@ -286,7 +282,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, message);
@@ -301,7 +297,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, message);
@@ -312,7 +308,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, mode);
 	call("onMode", 3);
@@ -322,7 +318,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, channel);
 	duk::push(m_context, names);
 	call("onNames", 3);
@@ -332,7 +328,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, oldnick);
 	duk::push(m_context, newnick);
 	call("onNick", 3);
@@ -342,7 +338,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, notice);
 	call("onNotice", 3);
@@ -356,7 +352,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, reason);
@@ -370,7 +366,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, message);
 	call("onQuery", 3);
@@ -383,7 +379,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, message);
 	call("onQueryCommand", 3);
@@ -404,7 +400,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	duk::push(m_context, server);
 	duk::push(m_context, origin);
 	duk::push(m_context, channel);
 	duk::push(m_context, topic);
@@ -425,7 +421,7 @@
 {
 	duk::StackAssert sa(m_context);
 
-	duk::push(m_context, duk::Shared<Server>{server});
+	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);
--- a/lib/irccd/plugin-js.hpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/plugin-js.hpp	Tue May 31 21:03:01 2016 +0200
@@ -39,7 +39,7 @@
 class JsPlugin : public Plugin {
 private:
 	// JavaScript context
-	duk::Context m_context;
+	duk::UniqueContext m_context;
 
 	// Store loaded modules.
 	std::vector<std::shared_ptr<Module>> m_modules;
@@ -67,7 +67,7 @@
 	 *
 	 * \return the context
 	 */
-	inline duk::Context &context() noexcept
+	inline duk::UniqueContext &context() noexcept
 	{
 		return m_context;
 	}
--- a/lib/irccd/server-event.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/lib/irccd/server-event.cpp	Tue May 31 21:03:01 2016 +0200
@@ -54,7 +54,7 @@
 		// TODO: get generic error.
 		try {
 			m_exec(*plugin);
-		} catch (const duk::ErrorInfo &info) {
+		} catch (const duk::Exception &info) {
 			log::warning() << "plugin " << plugin->name() << ": error: " << info.what() << std::endl;
 
 			if (!info.fileName.empty())
--- a/tests/js-elapsedtimer/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-elapsedtimer/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -46,12 +46,12 @@
 {
 	try {
 		if (duk::pevalString(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		std::this_thread::sleep_for(300ms);
 
 		if (duk::pevalString(m_plugin->context(), "result = timer.elapsed();") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_GE(duk::getGlobal<int>(m_plugin->context(), "result"), 250);
 		ASSERT_LE(duk::getGlobal<int>(m_plugin->context(), "result"), 350);
@@ -64,12 +64,12 @@
 {
 	try {
 		if (duk::pevalString(m_plugin->context(), "timer = new Irccd.ElapsedTimer();") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		std::this_thread::sleep_for(300ms);
 
 		if (duk::pevalString(m_plugin->context(), "timer.reset(); result = timer.elapsed();") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_LE(duk::getGlobal<int>(m_plugin->context(), "result"), 100);
 	} catch (const std::exception &ex) {
--- a/tests/js-file/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-file/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -45,7 +45,7 @@
 {
 	try {
 		if (duk::pevalString(m_plugin->context(), "result = Irccd.File.basename('/usr/local/etc/irccd.conf');") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("irccd.conf", duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -94,7 +94,7 @@
 
 	try {
 		if (duk::pevalString(m_plugin->context(), "Irccd.File.remove('test-js-fs.remove');") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -115,7 +115,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("file-1.txt", duk::getGlobal<std::string>(m_plugin->context(),"result"));
 	} catch (const std::exception &ex) {
@@ -135,7 +135,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("file-1.txt", duk::getGlobal<std::string>(m_plugin->context(),"result"));
 	} catch (const std::exception &ex) {
@@ -154,7 +154,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(std::string{IRCCD_TESTS_DIRECTORY "/level-1"}, duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -174,7 +174,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(std::string{IRCCD_TESTS_DIRECTORY "/level-1"}, duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -192,7 +192,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		std::vector<std::string> expected{"a", "b", "c"};
 
@@ -214,7 +214,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(".", duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -236,7 +236,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -257,7 +257,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(".", duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -280,7 +280,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -300,7 +300,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("x", duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -322,7 +322,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_TRUE(duk::getGlobal<bool>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -344,7 +344,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		std::vector<std::string> expected{"a", "b", "c"};
 
@@ -369,7 +369,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		std::vector<std::string> expected;
 
--- a/tests/js-irccd/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-irccd/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -48,7 +48,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(IRCCD_VERSION_MAJOR, duk::getGlobal<int>(m_plugin->context(), "major"));
 		ASSERT_EQ(IRCCD_VERSION_MINOR, duk::getGlobal<int>(m_plugin->context(), "minor"));
@@ -74,7 +74,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(1, duk::getGlobal<int>(m_plugin->context(), "errno"));
 		ASSERT_EQ("SystemError", duk::getGlobal<std::string>(m_plugin->context(), "name"));
@@ -89,7 +89,7 @@
 TEST_F(TestJsIrccd, fromNative)
 {
 	try {
-		duk::push(m_plugin->context(), duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret {
+		duk::push(m_plugin->context(), duk::Function{[] (duk::Context *ctx) -> duk::Ret {
 			duk::raise(ctx, SystemError{EINVAL, "hey"});
 
 			return 0;
@@ -110,7 +110,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ(EINVAL, duk::getGlobal<int>(m_plugin->context(), "errno"));
 		ASSERT_EQ("SystemError", duk::getGlobal<std::string>(m_plugin->context(), "name"));
--- a/tests/js-logger/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-logger/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -73,7 +73,7 @@
 		duk::putGlobal(m_plugin->context(), "\xff""\xff""name", "test");
 
 		if (duk::pevalString(m_plugin->context(), "Irccd.Logger.info(\"hello!\");") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("plugin test: hello!", lineInfo);
 	} catch (const std::exception &ex) {
@@ -87,7 +87,7 @@
 		duk::putGlobal(m_plugin->context(), "\xff""\xff""name", "test");
 
 		if (duk::pevalString(m_plugin->context(), "Irccd.Logger.warning(\"FAIL!\");") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("plugin test: FAIL!", lineWarning);
 	} catch (const std::exception &ex) {
@@ -103,7 +103,7 @@
 		duk::putGlobal(m_plugin->context(), "\xff""\xff""name", "test");
 
 		if (duk::pevalString(m_plugin->context(), "Irccd.Logger.debug(\"starting\");") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("plugin test: starting", lineDebug);
 	} catch (const std::exception &ex) {
--- a/tests/js-system/CMakeLists.txt	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-system/CMakeLists.txt	Tue May 31 21:03:01 2016 +0200
@@ -20,5 +20,6 @@
 	NAME js-system
 	SOURCES main.cpp
 	LIBRARIES libirccd
+	FLAGS IRCCD_EXECUTABLE=\"$<TARGET_FILE:irccd>\"
 )
 
--- a/tests/js-system/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-system/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -23,6 +23,7 @@
 #include <irccd/mod-system.hpp>
 #include <irccd/plugin-js.hpp>
 #include <irccd/service-module.hpp>
+#include <irccd/sysconfig.hpp>
 #include <irccd/system.hpp>
 
 using namespace irccd;
@@ -36,6 +37,7 @@
 		: m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
 	{
 		m_irccd.moduleService().get("Irccd")->load(m_irccd, *m_plugin);
+		m_irccd.moduleService().get("Irccd.File")->load(m_irccd, *m_plugin);
 		m_irccd.moduleService().get("Irccd.System")->load(m_irccd, *m_plugin);
 	}
 };
@@ -51,6 +53,27 @@
 	}
 }
 
+#if defined(HAVE_POPEN)
+
+TEST_F(TestJsSystem, popen)
+{
+	try {
+		auto ret = duk::pevalString(m_plugin->context(),
+			"f = Irccd.System.popen(\"" IRCCD_EXECUTABLE " --version\", \"r\");"
+			"r = f.readline();"
+		);
+
+		if (ret != 0)
+			throw duk::exception(m_plugin->context(), -1);
+
+		ASSERT_EQ(IRCCD_VERSION, duk::getGlobal<std::string>(m_plugin->context(), "r"));
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+}
+
+#endif
+
 int main(int argc, char **argv)
 {
 	testing::InitGoogleTest(&argc, argv);
--- a/tests/js-util/main.cpp	Thu May 26 21:20:46 2016 +0200
+++ b/tests/js-util/main.cpp	Tue May 31 21:03:01 2016 +0200
@@ -48,7 +48,7 @@
 		);
 
 		if (ret != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 	} catch (const std::exception &ex) {
 		FAIL() << ex.what();
 	}
@@ -58,7 +58,7 @@
 {
 	try {
 		if (duk::pevalString(m_plugin->context(), "result = Irccd.Util.splituser(\"user!~user@hyper/super/host\");") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("user", duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {
@@ -70,7 +70,7 @@
 {
 	try {
 		if (duk::pevalString(m_plugin->context(), "result = Irccd.Util.splithost(\"user!~user@hyper/super/host\");") != 0)
-			throw duk::error(m_plugin->context(), -1);
+			throw duk::exception(m_plugin->context(), -1);
 
 		ASSERT_EQ("!~user@hyper/super/host", duk::getGlobal<std::string>(m_plugin->context(), "result"));
 	} catch (const std::exception &ex) {