diff --git a/README.md b/README.md
index e7cb03f..15645db 100644
--- a/README.md
+++ b/README.md
@@ -12,536 +12,23 @@ This is a part of [Node3D](https://github.com/node-3d) project.
 
 ## Synopsis
 
-Helpers for Node.js **NAPI** addons and dependency packages:
-
-* Supported platforms (x64): Windows, Linux, OSX.
-* C++ helpers:
-	* Macro shortcuts for NAPI.
-	* `eventEmit()` function.
-	* `getData()` function.
-	* **Es5** class wrapper (like `Napi::ObjectWrap`, but Es5 functions).
-* Module helpers:
-	* Crossplatform commands for GYP: `cp`, `rm`, `mkdir`.
-	* Deps unzip installer.
-	* Url-to-buffer downloader.
-	* Binary copy helper.
-
-Useful links: [N-API Docs](https://nodejs.org/api/n-api.html),
-[Napi Docs](https://github.com/nodejs/node-addon-api/blob/master/doc/setup.md),
-[GYP Docs](https://gyp.gsrc.io/docs/UserDocumentation.md).
-
-**Jump to**:
-
-[Snippets](#snippets)
-
-[include/addon-tools.hpp](#includeaddon-toolshpp)
-
-[index.js](#indexjs)
-[cpbin.js](#cpbinjs)
-[download.js](#downloadjs)
-[install.js](#installjs)
-[writable-buffer.js](#writablebufferjs)
-
-[Crossplatform commands](#crossplatform-commands)
-
-[Function eventEmit](#function-eventEmit)
-
-[Es5 class wrapper](#es5-class-wrapper)
-
----
-
-
-## Snippets
-
-
-### Crossplatform commands
-
-```
-'variables': {
-	'rm'    : '<!(node -p "require(\'addon-tools-raub\').rm")',
-	'cp'    : '<!(node -p "require(\'addon-tools-raub\').cp")',
-	'mkdir' : '<!(node -p "require(\'addon-tools-raub\').mkdir")',
-},
-...
-'action': ['<(mkdir)', '-p', '<(binary)']
-```
-
-On both Windows and Unix those commands now have the same result.
-
-
-### Addon binary directory
-
-```
-'variables': {
-	'binary' : '<!(node -p "require(\'addon-tools-raub\').bin")',
-},
-```
-
-
-### Include directories
-
-```
-	'include_dirs': [
-		'<!@(node -p "require(\'addon-tools-raub\').include")',
-	],
-```
-
-Those are the directory paths to C++ include files for **Addon Tools** and
-**Napi** (which is preinstalled with Addon Tools).
-
-
-### Binary dependency package
-
-If you design a module with binary dependencies for several platforms,
-**Addon Tools** may help within the following guidelines:
-
-* In **package.json** use a `"postinstall"` script to download the libraries.
-For example the following structure might work. Note that **Addon Tools** will
-append any given URL with ``/${platform}.zip``
-	
-	```
-	"config" : {
-		"install" : "v1.0.0"
-	},
-	"scripts": {
-		"postinstall": "install",
-	},
-	```
-	
-	where `config.install` is  **YOUR install.js** is:
-	
-	```
-	const install = require('addon-tools-raub/install');
-	const prefix = 'https://github.com/user/addon/releases/download';
-	const tag = process.env.npm_package_config_install;
-	install(`${prefix}/${tag}`);
-	```
-	
-	**Addon Tools** will unzip the downloaded file into the platform binary
-	directory. E.g. on Windows it will be **bin-windows**.
-	
-* Per platform binary directories:
-	
-	* bin-windows
-	* bin-linux
-	* bin-osx
-	
-* The following piece of code in your `index.js` without changes. Method `paths()`
-is described [here](#indexjs).
-	
-	```
-	module.exports = require('addon-tools-raub').paths(__dirname);
-	```
-	
-* Publishing is done by attaching a zipped platform folder to the Github
-release. Zip file must NOT contain platform folder as a subfolder, but rather
-contain the final binaries. The tag of the release should be the same as in
-`npm_package_config_install` - that is the way installer will find it.
-	
-* NOTE: You can publish your binaries to anywhere, not necessarily Github.
-Just tweak **YOUR install.js** script as appropriate. The only limitation
-from **Addon Tools** is that it should be a zipped set of files/folders.
-
-
-### Compiled addon
-
-N-API ABI is compatible across Node.js versions, now addons
-are just plain DLLs. Therefore distribution of the binaries is covered in the
-previous section. But for an addon you have to provide a GYP compilation step.
-N-API changes it's role to out-of-install compilation, so we can't/shouldnt
-put the file **binding.gyp** to the module root anymore.
-
-The workaround would be to have a separate directory within your project
-(with simplified package.json) for the sake of addon compilation.
-
-```
-{
-	"name": "build",
-	"version": "0.0.0",
-	"private": true,
-	"dependencies": {
-		"addon-tools-raub": "5.0.0",
-		"deps-EXT_LIB": "1.0.0"
-	}
-}
-```
-
-* Assume `EXT_LIB` is the name of a binary dependency.
-* Assume `deps-EXT_LIB` is the name of an Addon Tools compliant dependency module.
-* Assume `MY_ADDON` is the name of this addon's resulting binary.
-* Assume C++ code goes to `cpp` subdirectory.
-
-That together with **binding.gyp**, this would be enough to get the addon compiled.
-Then the binaries are published to the Github release. When the addon
-is installed, its **index.js** is responsible for reexport of the binary.
-Just require the built module like this:
-
-```
-const { bin } = require('addon-tools-raub');
-const core = require(`./${bin}/MY_ADDON`);
-```
-
-<details>
-
-<summary>See a snipped for binding.gyp here</summary>
-
-* Assume `EXT_LIB` is the name of a binary dependency.
-* Assume `deps-EXT_LIB` is the name of an Addon Tools compliant dependency module.
-* Assume `MY_ADDON` is the name of this addon's resulting binary.
-* Assume C++ code goes to `cpp` subdirectory.
-
-```
-{
-	'variables': {
-		'rm'              : '<!(node -e "require(\'addon-tools-raub\').rm")',
-		'cp'              : '<!(node -e "require(\'addon-tools-raub\').cp")',
-		'mkdir'           : '<!(node -e "require(\'addon-tools-raub\').mkdir")',
-		'binary'          : '<!(node -e "require(\'addon-tools-raub\').bin")',
-		'EXT_LIB_include' : '<!(node -e "require(\'deps-EXT_LIB\').include")',
-		'EXT_LIB_bin'     : '<!(node -e "require(\'deps-EXT_LIB\').bin")',
-	},
-	'targets': [
-		{
-			'target_name': 'MY_ADDON',
-			'sources': [
-				'cpp/MY_ADDON.cpp',
-			],
-			'include_dirs': [
-				'<!(node -e "require(\'addon-tools-raub\').include")',
-				'<(EXT_LIB_include)',
-				'<(module_root_dir)/include',
-			],
-			'library_dirs': [ '<(EXT_LIB_bin)' ],
-			'conditions': [
-				[
-					'OS=="linux"',
-					{
-						'libraries': [
-							'-Wl,-rpath,<(EXT_LIB_bin)',
-							'<(EXT_LIB_bin)/libEXT_LIB.so',
-						],
-					}
-				],
-				[
-					'OS=="mac"',
-					{
-						'libraries': [
-							'-Wl,-rpath,<(EXT_LIB_bin)',
-							'<(EXT_LIB_bin)/EXT_LIB.dylib',
-						],
-						'xcode_settings': {
-							'DYLIB_INSTALL_NAME_BASE': '@rpath',
-						},
-					}
-				],
-				[
-					'OS=="win"',
-					{
-						'libraries': [ 'EXT_LIB.lib' ],
-						'defines' : [
-							'WIN32_LEAN_AND_MEAN',
-							'VC_EXTRALEAN'
-						],
-						'msvs_version'  : '2013',
-						'msvs_settings' : {
-							'VCCLCompilerTool' : {
-								'AdditionalOptions' : [
-									'/O2','/Oy', # Comment this for debugging
-									# '/Z7', # Unomment this for debugging
-									'/GL','/GF','/Gm-','/EHsc',
-									'/MT','/GS','/Gy','/GR-','/Gd',
-								]
-							},
-							'VCLinkerTool' : {
-								'AdditionalOptions' : ['/OPT:REF','/OPT:ICF','/LTCG']
-							},
-						},
-					}
-				],
-			],
-		},
-		
-		{
-			'target_name'  : 'make_directory',
-			'type'         : 'none',
-			'dependencies' : ['MY_ADDON'],
-			'actions'      : [{
-				'action_name' : 'Directory created.',
-				'inputs'      : [],
-				'outputs'     : ['build'],
-				'action': ['<(mkdir)', '-p', '<(binary)']
-			}],
-		},
-		{
-			'target_name'  : 'copy_binary',
-			'type'         : 'none',
-			'dependencies' : ['make_directory'],
-			'actions'      : [{
-				'action_name' : 'Module copied.',
-				'inputs'      : [],
-				'outputs'     : ['binary'],
-				'action'      : [
-					'<(cp)',
-					'build/Release/MY_ADDON.node',
-					'<(binary)/MY_ADDON.node',
-				],
-			}],
-		},
-		
-	]
-}
-```
-
-</details>
-
----
-
-
-## include/addon-tools.hpp
-
-There is a C++ header file, `addon-tools.hpp`, shipped with this package. It
-introduces several useful macros and utilities. Also it includes Napi automatically,
-so that you can replace:
-
-```
-#include <napi.h>
-```
-
-with
-
-```
-#include <addon-tools.hpp>
-```
-
-In gyp, the include directory should be set for your addon to know where
-to get it. An actual path to the directory is exported from the module
-and is accessible like this:
-
-```
-require('addon-tools-raub').include // a string
-```
-
-### Helpers in **addon-tools.hpp**:
-
-Usually all the helpers work within the context of JS call. In this case we
-have `CallbackInfo info` passed as an argument.
-
-```
-#define NAPI_ENV Napi::Env env = info.Env();
-#define NAPI_HS Napi::HandleScope scope(env);
-```
-
-<details>
-
-<summary>Return value</summary>
-
-* `RET_VALUE(VAL)`- return a given Napi::Value.
-* `RET_UNDEFINED`- return `undefined`.
-* `RET_NULL` - return `null`.
-* `RET_STR(VAL)` - return `Napi::String`, expected `VAL` is `const char *`.
-* `RET_NUM(VAL)` - return `Napi::Number`, expected `VAL` is `double`.
-* `RET_EXT(VAL)` - return `Napi::External`, expected `VAL` is `void *`.
-* `RET_BOOL(VAL)` - return `Napi::Boolean`, expected `VAL` is `bool`.
-* `RET_FUN(VAL)` - return `Napi::Function`, expected `VAL` is a `napi_value`.
-* `RET_OBJ(VAL)` - return `Napi::Object`, expected `VAL` is a `napi_value`.
-
-</details>
-
-
-
-<details>
-
-<summary>New JS value</summary>
-
-* `JS_STR(VAL)` - create a `Napi::String` value.
-* `JS_NUM(VAL)` - create a `Napi::Number` value.
-* `JS_EXT(VAL)` - create a `Napi::External` (from pointer) value.
-* `JS_BOOL(VAL)` - create a `Napi::Boolean` value.
-* `JS_FUN(VAL)` - create a `Napi::Function` value.
-* `JS_OBJ(VAL)` - create a `Napi::Object` value.
-
-</details>
-
-
-<details>
-
-<summary>Method check</summary>
-
-These checks throw JS TypeError if not passed. Here `T` is always used as a typename
-in error messages. `C` is a
-[Napi::Value](https://github.com/nodejs/node-addon-api/blob/master/doc/value.md#isboolean)
-check method, like `IsObject()`. `I` is the index of argument as in `info[I]`,
-starting from `0`.
-
-* `REQ_ARGS(N)` - check if at least `N` arguments passed
-* `IS_ARG_EMPTY(I)` - check if argument `I` is `undefined` or `null`
-* `CHECK_REQ_ARG(I, C, T)` - check if argument `I` is approved by `C` check.
-* `CHECK_LET_ARG(I, C, T)` - check if argument `I` is approved by `C` check or empty.
-* `CTOR_CHECK(T)` - check if method is called as a constructor
-* `SETTER_CHECK(C, T)` - check if setter `value` is approved by `C` check.
-* `DES_CHECK` - within dynamic method check if the instance wasn't
-destroyed by `destroy()`.
-
-</details>
-
-
-<details>
-
-<summary>Method arguments</summary>
-
-The idea is to ease the transition from what inside the `CallbackInfo` to
-what you work with in C++.
-Three types of argument retrieval are supported: `REQ_`, `USE_` and `LET_`.
-The difference:
-* `REQ_` - 2 params, requires an argument to have a value
-* `USE_` - 3 params, allows the argument to be empty and have a default
-* `LET_` - 2 params, is `USE_` with a preset zero-default.
-
-What it does, basically:
-```
-// REQ_DOUBLE_ARG(0, x)
-double x = info[0].ToNumber().DoubleValue();
-
-// USE_DOUBLE_ARG(0, x, 5.7)
-double x = IS_ARG_EMPTY(0) ? 5.7 : info[0].ToNumber().DoubleValue();
-
-// LET_DOUBLE_ARG(0, x)
-double x = IS_ARG_EMPTY(0) ? 0.0 : info[0].ToNumber().DoubleValue();
-```
-
-That extrapolates well to all the helpers below:
-* `REQ_STR_ARG` - JS `string` => C++ `std::string`.
-* `USE_STR_ARG`
-* `LET_STR_ARG` - default: `""`.
-* `REQ_INT32_ARG` - JS `number` => C++ `int32_t`.
-* `USE_INT32_ARG`
-* `LET_INT32_ARG` - default: `0`.
-* `REQ_INT_ARG` - JS `number` => C++ `int32_t`.
-* `USE_INT_ARG`
-* `LET_INT_ARG` - default: `0`.
-* `REQ_UINT32_ARG` - JS `number` => C++ `uint32_t`.
-* `USE_UINT32_ARG`
-* `LET_UINT32_ARG` - default: `0`.
-* `REQ_UINT_ARG` - JS `number` => C++ `uint32_t`.
-* `USE_UINT_ARG`
-* `LET_UINT_ARG` - default: `0`.
-* `REQ_BOOL_ARG` - JS `Boolean` => C++ `bool`.
-* `USE_BOOL_ARG`
-* `LET_BOOL_ARG` - default: `false`.
-* `REQ_OFFS_ARG` - JS `number` => C++ `size_t`.
-* `USE_OFFS_ARG`
-* `LET_OFFS_ARG` - default: `0`.
-* `REQ_DOUBLE_ARG` - JS `number` => C++ `double`.
-* `USE_DOUBLE_ARG`
-* `LET_DOUBLE_ARG` - default: `0.0`.
-* `REQ_FLOAT_ARG` - JS `number` => C++ `float`.
-* `USE_FLOAT_ARG`
-* `LET_FLOAT_ARG` - default: `0.f`.
-* `REQ_EXT_ARG` - JS `native` => C++ `void*`.
-* `USE_EXT_ARG`
-* `LET_EXT_ARG` - default: `nullptr`.
-* `REQ_FUN_ARG` - JS `function` => C++ `Napi::Function`.
-* `REQ_OBJ_ARG` - JS `object` => C++ `Napi::Object`.
-* `USE_OBJ_ARG`
-* `LET_OBJ_ARG` - default: `{}`.
-* `REQ_ARRV_ARG` - JS `ArrayBuffer` => C++ `Napi::ArrayBuffer`.
-* `REQ_BUF_ARG` - JS `Buffer` => C++ `Napi::Buffer<uint8_t>`.
-
-
-```
-NAN_METHOD(test) {
-	
-	REQ_UINT32_ARG(0, width);
-	REQ_UINT32_ARG(1, height);
-	LET_FLOAT_ARG(2, z);
-	// Variables created: unsigned int width, height; float z;
-	...
-```
-
-</details>
-
-
-<details>
-
-<summary>Set object accessors</summary>
-
-Simplified accessor assignment, adds accessors of NAME for OBJ. Read accessor is
-assumed to have the name `NAME+'Getter'` and write accessor is `NAME+'Setter'`.
-
-* `ACCESSOR_RW(CLASS, NAME)` - add read and write accessors NAME of CLASS.
-* `ACCESSOR_R(CLASS, NAME)` - add read accessor NAME of CLASS.
-* `ACCESSOR_M(CLASS, NAME)` - add method NAME of CLASS.
-
-
-```
-void MyClass::init(Napi::Env env, Napi::Object exports) {
-	...
-	Napi::Function ctor = DefineClass(env, "MyClass", {
-		ACCESSOR_R(MyClass, isDestroyed),
-		ACCESSOR_RW(MyClass, x),
-		ACCESSOR_M(MyClass, reset),
-	});
-	...
-}
-JS_GETTER(MyClass::isDestroyedGetter) { ...
-JS_GETTER(MyClass::xGetter) { ...
-JS_SETTER(MyClass::xSetter) { ...
-JS_METHOD(MyClass::save) { ...
-```
-
-</details>
-
-
-<details>
-
-<summary>Setter argument</summary>
-
-Works similar to method arguments. But there is always `value`
-argument, from which a C++ value is extracted.
-
-* `SETTER_STR_ARG`
-* `SETTER_INT32_ARG`
-* `SETTER_INT_ARG`
-* `SETTER_BOOL_ARG`
-* `SETTER_UINT32_ARG`
-* `SETTER_UINT_ARG`
-* `SETTER_OFFS_ARG`
-* `SETTER_DOUBLE_ARG`
-* `SETTER_FLOAT_ARG`
-* `SETTER_EXT_ARG`
-* `SETTER_FUN_ARG`
-* `SETTER_OBJ_ARG`
-* `SETTER_ARRV_ARG`
-
-```
-JS_SETTER(MyClass::x) { SETTER_STR_ARG;
-	// Variable created: std::string v;
-	...
-```
-
-</details>
-
-
-<details>
-
-<summary>Data retrieval</summary>
-
-* `T *getArrayData(value, num = NULL)` - extracts TypedArray data of any type from
-the given JS value. Does not accept `Array`. Checks with `IsArrayBuffer()`.
-Returns `nullptr` for empty JS values. For unacceptable values throws TypeError.
-
-* `void *getData(value)` - if value is a TypedArray, then the result of
-`getArrayData(value)` is returned. Otherwise if value has `'data'` property, it's
-content is then returned as `node::Buffer`. Returns `nullptr` in other cases.
-
-</details>
-
----
+Helpers for Node.js **NAPI** addons and dependency packages.
+
+**Go to**:
+
+[include/addon-tools.hpp](doc/addon-tools.md)
+Macro shortcuts for NAPI.
+[Es5 Class Wrapping](doc/class-wrapping.md)
+An alternative, lightweight native class-defining mechanism for addons.
+* [Script Helpers](doc/script-helpers.md)
+Additional scripts for addon management.
+* [Snippets](doc/snippets.md)
+Some repetitive bits of code for addons.
 
 
 ## index.js
 
-Exports:
+Main exports for cross-platform addon configuration. Exports:
 * `paths(dir)` - function. Returns a set of platform dependent paths depending on
 input `dir`.
 	* `bin` - platform binary directory absolute path.
@@ -552,105 +39,3 @@ Use with `node -p` through list context command expansion `<!@(...)`
 * `cp` - the location of `'_cp.bat'` file on Windows and plain `cp` on Unix.
 * `mkdir` - the location of `'_mkdir.bat'` file on Windows and plain `mkdir` on Unix.
 * `bin` - platform binary directory name.
-
----
-
-
-### mkdir
-
-On Unix, it will be an actual system `mkdir`, whereas on Windows it will use the
-**mkdir.bat** file, located at the root of this package. This BAT file behaves
-as if it was a `mkdir -p ...` call. You can still pass `-p` switch, which is
-ignored. And the limitation is that you can not create a relative-path **-p**
-folder. This can possibly be bypassed by supplying `./-p` or something like this.
-
-
-```
-'variables': {
-	'mkdir' : '<!(node -p "require(\'addon-tools-raub\').mkdir")',
-},
-...
-'action' : ['<(mkdir)', '-p', 'binary'],
-```
-
-
-### rm
-
-Disregard `del` and `rd` on Windows command line. Now the same command can
-be used on all platforms to remove single and multiple files and directories.
-
-```
-'variables': {
-	'rm'  : '<!(node -e "require(\'addon-tools-raub\').rm")',
-},
-...
-'action' : ['<(rm)', '-rf', 'dirname'],
-```
-
-### cp
-
-For Windows the `/y` flag was embedded.
-
-```
-'variables': {
-	'cp'  : '<!(node -e "require(\'addon-tools-raub\').cp")',
-},
-...
-'action' : ['<(cp)', 'a', 'b'],
-```
-
-
-## Function consoleLog
-
-In C++ addons, the use of **iostream** is discouraged because **Node.js** has its own
-perspective on **stdout** behavior.
-At first it may look as if `cout << "msg" << endl;` works nice, but it doesn't.
-After a while, it just ceases on a midword, and you end up thinking something has
-broken really hard in your addon.
-
-To overcome this, we can use some `eval` magic to make a real `console.log`
-call from C++ land. And this is where `consoleLog` comes into play.
-
-* `inline void consoleLog(int argc, V8_VAR_VAL *argv)` - a generic logger,
-receives any set of arguments.
-
-* `inline void consoleLog(const std::string &message)` - an alias to log a single
-string.
-
-> Note: only use this within JS function stack
-
-
-## Function eventEmit
-
-In N-API there is no inheritance. And no `eval('require(...)')` possible at
-the time of module init. But `require('events')` is very tempting...
-The solution is:
-
-```
-// JS
-const EventEmitter = require('events');
-const { bin } = require('addon-tools-raub');
-const MyClass = require(`./${bin}/addon`);
-MyClass.prototype.__proto__ = EventEmitter.prototype;
-// Since now it is possible to call `emit` from instancess of MyClass
-```
-
-```
-// C++
-void MyClass::emit(const Napi::CallbackInfo& info, const char* name) {
-	NAPI_ENV;
-	THIS_OBJ(that);
-	eventEmit(env, that, name);
-}
-```
-
-Signature:
-```
-inline void eventEmit(
-	Napi::Env env,
-	Napi::Object that,
-	const std::string &name,
-	int argc = 0,
-	Napi::Value *argv = nullptr
-)
-```
diff --git a/bat/cp.bat b/bat/cp.bat
deleted file mode 100644
index 1f14d31..0000000
--- a/bat/cp.bat
+++ /dev/null
@@ -1 +0,0 @@
-copy /y %1 %2
diff --git a/bat/mkdir.bat b/bat/mkdir.bat
deleted file mode 100644
index 6fd346a..0000000
--- a/bat/mkdir.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-for %%x in (%*) do (
-	
-	if not %%x=="-p" if not exist %%x md %%x
-	
-)
diff --git a/bat/rm.bat b/bat/rm.bat
deleted file mode 100644
index 48dd3b5..0000000
--- a/bat/rm.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-for %%x in (%*) do (
-	
-	if not %%x=="-rf" if not %%x=="-r" if not %%x=="-f" if exist %%~x\ rd /s /q %%x
-	if not %%x=="-rf" if not %%x=="-r" if not %%x=="-f" if not exist %%~x\ if exist %%x del /f /q %%x
-	
-)
diff --git a/doc/addon-tools.md b/doc/addon-tools.md
new file mode 100644
index 0000000..525f802
--- /dev/null
+++ b/doc/addon-tools.md
@@ -0,0 +1,238 @@
+# include/addon-tools.hpp
+
+There is a C++ header file, `addon-tools.hpp`, shipped with this package. It
+introduces several useful macros and utilities. Also it includes Napi automatically,
+so that you can replace:
+
+```
+#include <napi.h>
+```
+
+with
+
+```
+#include <addon-tools.hpp>
+```
+
+In gyp, the include directory should be set for your addon to know where
+to get it. An actual path to the directory is exported from the module
+and is accessible like this:
+
+```
+require('addon-tools-raub').include // a string
+```
+
+### Helpers in **addon-tools.hpp**:
+
+Usually all the helpers work within the context of JS call. In this case we
+have `CallbackInfo info` passed as an argument.
+
+```
+#define NAPI_ENV Napi::Env env = info.Env();
+#define NAPI_HS Napi::HandleScope scope(env);
+```
+
+<details>
+
+<summary>Return value</summary>
+
+* `RET_VALUE(VAL)`- return a given Napi::Value.
+* `RET_UNDEFINED`- return `undefined`.
+* `RET_NULL` - return `null`.
+* `RET_STR(VAL)` - return `Napi::String`, expected `VAL` is `const char *`.
+* `RET_NUM(VAL)` - return `Napi::Number`, expected `VAL` is `double`.
+* `RET_EXT(VAL)` - return `Napi::External`, expected `VAL` is `void *`.
+* `RET_BOOL(VAL)` - return `Napi::Boolean`, expected `VAL` is `bool`.
+* `RET_FUN(VAL)` - return `Napi::Function`, expected `VAL` is a `napi_value`.
+* `RET_OBJ(VAL)` - return `Napi::Object`, expected `VAL` is a `napi_value`.
+
+</details>
+
+
+
+<details>
+
+<summary>New JS value</summary>
+
+* `JS_STR(VAL)` - create a `Napi::String` value.
+* `JS_NUM(VAL)` - create a `Napi::Number` value.
+* `JS_EXT(VAL)` - create a `Napi::External` (from pointer) value.
+* `JS_BOOL(VAL)` - create a `Napi::Boolean` value.
+* `JS_FUN(VAL)` - create a `Napi::Function` value.
+* `JS_OBJ(VAL)` - create a `Napi::Object` value.
+
+</details>
+
+
+<details>
+
+<summary>Method check</summary>
+
+These checks throw JS TypeError if not passed. Here `T` is always used as a typename
+in error messages. `C` is a
+[Napi::Value](https://github.com/nodejs/node-addon-api/blob/master/doc/value.md#isboolean)
+check method, like `IsObject()`. `I` is the index of argument as in `info[I]`,
+starting from `0`.
+
+* `REQ_ARGS(N)` - check if at least `N` arguments passed
+* `IS_ARG_EMPTY(I)` - check if argument `I` is `undefined` or `null`
+* `CHECK_REQ_ARG(I, C, T)` - check if argument `I` is approved by `C` check.
+* `CHECK_LET_ARG(I, C, T)` - check if argument `I` is approved by `C` check or empty.
+* `CTOR_CHECK(T)` - check if method is called as a constructor
+* `SETTER_CHECK(C, T)` - check if setter `value` is approved by `C` check.
+* `DES_CHECK` - within dynamic method check if the instance wasn't
+destroyed by `destroy()`.
+
+</details>
+
+
+<details>
+
+<summary>Method arguments</summary>
+
+The idea is to ease the transition from what inside the `CallbackInfo` to
+what you work with in C++.
+Three types of argument retrieval are supported: `REQ_`, `USE_` and `LET_`.
+The difference:
+* `REQ_` - 2 params, requires an argument to have a value
+* `USE_` - 3 params, allows the argument to be empty and have a default
+* `LET_` - 2 params, is `USE_` with a preset zero-default.
+
+What it does, basically:
+```
+// REQ_DOUBLE_ARG(0, x)
+double x = info[0].ToNumber().DoubleValue();
+
+// USE_DOUBLE_ARG(0, x, 5.7)
+double x = IS_ARG_EMPTY(0) ? 5.7 : info[0].ToNumber().DoubleValue();
+
+// LET_DOUBLE_ARG(0, x)
+double x = IS_ARG_EMPTY(0) ? 0.0 : info[0].ToNumber().DoubleValue();
+```
+
+That extrapolates well to all the helpers below:
+* `REQ_STR_ARG` - JS `string` => C++ `std::string`.
+* `USE_STR_ARG`
+* `LET_STR_ARG` - default: `""`.
+* `REQ_INT32_ARG` - JS `number` => C++ `int32_t`.
+* `USE_INT32_ARG`
+* `LET_INT32_ARG` - default: `0`.
+* `REQ_INT_ARG` - JS `number` => C++ `int32_t`.
+* `USE_INT_ARG`
+* `LET_INT_ARG` - default: `0`.
+* `REQ_UINT32_ARG` - JS `number` => C++ `uint32_t`.
+* `USE_UINT32_ARG`
+* `LET_UINT32_ARG` - default: `0`.
+* `REQ_UINT_ARG` - JS `number` => C++ `uint32_t`.
+* `USE_UINT_ARG`
+* `LET_UINT_ARG` - default: `0`.
+* `REQ_BOOL_ARG` - JS `Boolean` => C++ `bool`.
+* `USE_BOOL_ARG`
+* `LET_BOOL_ARG` - default: `false`.
+* `REQ_OFFS_ARG` - JS `number` => C++ `size_t`.
+* `USE_OFFS_ARG`
+* `LET_OFFS_ARG` - default: `0`.
+* `REQ_DOUBLE_ARG` - JS `number` => C++ `double`.
+* `USE_DOUBLE_ARG`
+* `LET_DOUBLE_ARG` - default: `0.0`.
+* `REQ_FLOAT_ARG` - JS `number` => C++ `float`.
+* `USE_FLOAT_ARG`
+* `LET_FLOAT_ARG` - default: `0.f`.
+* `REQ_EXT_ARG` - JS `native` => C++ `void*`.
+* `USE_EXT_ARG`
+* `LET_EXT_ARG` - default: `nullptr`.
+* `REQ_FUN_ARG` - JS `function` => C++ `Napi::Function`.
+* `REQ_OBJ_ARG` - JS `object` => C++ `Napi::Object`.
+* `USE_OBJ_ARG`
+* `LET_OBJ_ARG` - default: `{}`.
+* `REQ_ARRV_ARG` - JS `ArrayBuffer` => C++ `Napi::ArrayBuffer`.
+* `REQ_BUF_ARG` - JS `Buffer` => C++ `Napi::Buffer<uint8_t>`.
+
+
+```
+NAN_METHOD(test) {
+	
+	REQ_UINT32_ARG(0, width);
+	REQ_UINT32_ARG(1, height);
+	LET_FLOAT_ARG(2, z);
+	// Variables created: unsigned int width, height; float z;
+	...
+```
+
+</details>
+
+
+<details>
+
+<summary>Set object accessors</summary>
+
+Simplified accessor assignment, adds accessors of NAME for OBJ. Read accessor is
+assumed to have the name `NAME+'Getter'` and write accessor is `NAME+'Setter'`.
+
+* `ACCESSOR_RW(CLASS, NAME)` - add read and write accessors NAME of CLASS.
+* `ACCESSOR_R(CLASS, NAME)` - add read accessor NAME of CLASS.
+* `ACCESSOR_M(CLASS, NAME)` - add method NAME of CLASS.
+
+
+```
+void MyClass::init(Napi::Env env, Napi::Object exports) {
+	...
+	Napi::Function ctor = DefineClass(env, "MyClass", {
+		ACCESSOR_R(MyClass, isDestroyed),
+		ACCESSOR_RW(MyClass, x),
+		ACCESSOR_M(MyClass, reset),
+	});
+	...
+}
+JS_GETTER(MyClass::isDestroyedGetter) { ...
+JS_GETTER(MyClass::xGetter) { ...
+JS_SETTER(MyClass::xSetter) { ...
+JS_METHOD(MyClass::save) { ...
+```
+
+</details>
+
+
+<details>
+
+<summary>Setter argument</summary>
+
+Works similar to method arguments. But there is always `value`
+argument, from which a C++ value is extracted.
+
+* `SETTER_STR_ARG`
+* `SETTER_INT32_ARG`
+* `SETTER_INT_ARG`
+* `SETTER_BOOL_ARG`
+* `SETTER_UINT32_ARG`
+* `SETTER_UINT_ARG`
+* `SETTER_OFFS_ARG`
+* `SETTER_DOUBLE_ARG`
+* `SETTER_FLOAT_ARG`
+* `SETTER_EXT_ARG`
+* `SETTER_FUN_ARG`
+* `SETTER_OBJ_ARG`
+* `SETTER_ARRV_ARG`
+
+```
+JS_SETTER(MyClass::x) { SETTER_STR_ARG;
+	// Variable created: std::string v;
+	...
+```
+
+</details>
+
+
+<details>
+
+<summary>Data retrieval</summary>
+
+* `T *getArrayData(value, num = NULL)` - extracts TypedArray data of any type from
+the given JS value. Does not accept `Array`. Checks with `IsArrayBuffer()`.
+Returns `nullptr` for empty JS values. For unacceptable values throws TypeError.
+
+* `void *getData(value)` - if value is a TypedArray, then the result of
+`getArrayData(value)` is returned. Otherwise if value has `'data'` property, it's
+content is then returned as `node::Buffer`. Returns `nullptr` in other cases.
+
+</details>
diff --git a/doc/class-wrapping.md b/doc/class-wrapping.md
new file mode 100644
index 0000000..c9a368a
--- /dev/null
+++ b/doc/class-wrapping.md
@@ -0,0 +1 @@
+# Es5 class wrapping
diff --git a/doc/script-helpers.md b/doc/script-helpers.md
new file mode 100644
index 0000000..5b755c2
--- /dev/null
+++ b/doc/script-helpers.md
@@ -0,0 +1 @@
+# Script Helpers
diff --git a/doc/snippets.md b/doc/snippets.md
new file mode 100644
index 0000000..2b7a19e
--- /dev/null
+++ b/doc/snippets.md
@@ -0,0 +1,197 @@
+# Snippets
+
+## C++ Addon building
+
+N-API addons are built separately from the installation, so we can't/shouldn't
+put the file **binding.gyp** to the module root anymore. It is better to have a
+separate folder with a separate **package.json**, **binding.gyp** and the sources.
+
+A snippet for **src/package.json**:
+```
+{
+	"name": "build",
+	"version": "0.0.0",
+	"private": true,
+	"scripts": {
+		"build": "node-gyp rebuild && node -e \"require('addon-tools-raub/cpbin')('ADDON')\""
+	},
+	"dependencies": {
+		"addon-tools-raub": "5.0.0",
+		"DEPS": "1.0.0"
+	}
+}
+```
+
+* `ADDON` - the name of this addon (and subsequently of its binary).
+* `DEPS` - dependency package(s).
+
+
+
+### Binary distribution
+
+In **package.json** use the `"postinstall"` script to download the libraries.
+For example the following structure might work. Note that **Addon Tools** will
+append any given URL with `/${platform}.zip`
+
+```
+	"config" : {
+		"install" : "v1.0.0"
+	},
+	"scripts": {
+		"postinstall": "install",
+	},
+```
+
+Here `config.install` is the tag name to download the binaries from.
+To use it, create the *install.js* file in your addon:
+
+```
+const install = require('addon-tools-raub/install');
+const prefix = 'https://github.com/USER/ADDON/releases/download';
+const tag = process.env.npm_package_config_install;
+install(`${prefix}/${tag}`);
+```
+
+**Addon Tools** will unzip the downloaded file into the platform binary
+directory. E.g. on Windows it will be **bin-windows**.
+
+* For a dependency package:
+	
+	Place the following piece of code in the `index.js` without changes. Method `paths()`
+	is described [here](../README.md).
+	```
+	module.exports = require('addon-tools-raub').paths(__dirname);
+	```
+	
+* For a compiled addon:
+	
+	Require it in your **index.js** from the platform-specific directory.
+	```
+	const { bin } = require('addon-tools-raub');
+	const core = require(`./${bin}/ADDON`);
+	```
+
+
+Publishing binaries is done by attaching a zipped platform folder to the Github
+release. Zip file must NOT contain platform folder as a subfolder, but rather
+contain the final binaries. The tag of the release should be the same as in
+`npm_package_config_install` - that is the way installer will find it.
+
+> NOTE: You can publish your binaries to anywhere, not necessarily Github.
+Just tweak **YOUR install.js** script as appropriate. The only limitation
+from **Addon Tools** is that it should be a zipped set of files/folders.
+
+
+### GYP Variables
+
+```
+	'variables': {
+		'bin'          : '<!(node -p "require(\'addon-tools-raub\').bin")',
+		'DEPS_include' : '<!(node -p "require(\'DEPS\').include")',
+		'DEPS_bin'     : '<!(node -p "require(\'DEPS\').bin")',
+	},
+```
+
+* `bin` - the name of this platform's binary directory, e.g. *bin-linux*.
+* `DEPS_include` - the include folder for some dependency package.
+* `DEPS_bin` - the binary folder for some dependency package.
+
+
+
+### Include directories
+
+```
+	'include_dirs' : [
+		'<!@(node -p "require(\'addon-tools-raub\').include")',
+		'<(DEPS_include)',
+	],
+```
+
+The former contains both the path to include **Addon Tools** and the one for
+**Napi** (which is preinstalled with Addon Tools). The latter can be any other
+dependency include path(s).
+
+
+<details>
+
+<summary>See a snipped for src/binding.gyp here</summary>
+
+* Assume `DEPS` is the name of an Addon Tools compliant dependency module.
+* Assume `ADDON` is the name of this addon's resulting binary.
+* Assume C++ code goes to `cpp` subdirectory.
+
+```
+{
+	'variables': {
+		'bin'          : '<!(node -p "require(\'addon-tools-raub\').bin")',
+		'DEPS_include' : '<!(node -p "require(\'DEPS\').include")',
+		'DEPS_bin'     : '<!(node -p "require(\'DEPS\').bin")',
+	},
+	'targets': [
+		{
+			'target_name' : 'bullet',
+			'sources' : [
+				'cpp/addon.cpp',
+			],
+			'include_dirs' : [
+				'<!@(node -p "require(\'addon-tools-raub\').include")',
+				'<(DEPS_include)',
+			],
+			'library_dirs' : [ '<(DEPS_bin)' ],
+			'libraries'    : [ '-lDEPS' ],
+			'cflags!': ['-fno-exceptions'],
+			'cflags_cc!': ['-fno-exceptions'],
+			'conditions': [
+				
+				[
+					'OS=="linux"',
+					{
+						'libraries': [
+							"-Wl,-rpath,'$$ORIGIN'",
+							"-Wl,-rpath,'$$ORIGIN/../node_modules/DEPS/<(bin)'",
+							"-Wl,-rpath,'$$ORIGIN/../../DEPS/<(bin)'",
+						],
+						'defines': ['__linux__'],
+					}
+				],
+				
+				[
+					'OS=="mac"',
+					{
+						'libraries': [
+							'-Wl,-rpath,@loader_path',
+							'-Wl,-rpath,@loader_path/../node_modules/DEPS/<(bin)',
+							'-Wl,-rpath,@loader_path/../../DEPS/<(bin)',
+						],
+						'defines': ['__APPLE__'],
+					}
+				],
+				
+				[
+					'OS=="win"',
+					{
+						'defines' : [
+							'WIN32_LEAN_AND_MEAN',
+							'VC_EXTRALEAN',
+							'_WIN32',
+						],
+						'msvs_settings' : {
+							'VCCLCompilerTool' : {
+								'AdditionalOptions' : [
+									'/GL', '/GF', '/EHsc', '/GS', '/Gy', '/GR-',
+								]
+							},
+							'VCLinkerTool' : {
+								'AdditionalOptions' : ['/RELEASE','/OPT:REF','/OPT:ICF','/LTCG'],
+							},
+						},
+					},
+				],
+				
+			],
+		},
+	]
+}
+```
+
+</details>
diff --git a/include/addon-tools.hpp b/include/addon-tools.hpp
index 5e6b611..ebdca20 100644
--- a/include/addon-tools.hpp
+++ b/include/addon-tools.hpp
@@ -1,5 +1,5 @@
-#ifndef _ADDON_TOOLS_HPP_
-#define _ADDON_TOOLS_HPP_
+#ifndef ADDON_TOOLS_HPP
+#define ADDON_TOOLS_HPP
 
 #define NODE_ADDON_API_DISABLE_DEPRECATED
 #define NAPI_DISABLE_CPP_EXCEPTIONS
@@ -7,7 +7,7 @@
 
 
 #ifdef _WIN32
-	#define	strcasestr(s, t) strstr(strupr(s), strupr(t))
+	#define strcasestr(s, t) strstr(strupr(s), strupr(t))
 #endif
 
 
@@ -41,6 +41,7 @@
 #define REQ_ARGS(N)                                                           \
 	if (info.Length() < (N)) {                                                \
 		JS_THROW("Expected at least " #N " arguments");                       \
+		RET_UNDEFINED;                                                        \
 	}
 
 
@@ -51,6 +52,7 @@
 #define CHECK_REQ_ARG(I, C, T)                                                \
 	if (info.Length() <= (I) || ! info[I].C) {                                \
 		JS_THROW("Argument " #I " must be of type `" T "`");                  \
+		RET_UNDEFINED;                                                        \
 	}
 
 #define CHECK_LET_ARG(I, C, T)                                                \
@@ -60,6 +62,7 @@
 			" must be of type `" T                                            \
 			"` or be `null`/`undefined`"                                      \
 		);                                                                    \
+		RET_UNDEFINED;                                                        \
 	}
 
 
@@ -195,6 +198,7 @@
 	REQ_OBJ_ARG(I, _obj_##VAR);                                               \
 	if ( ! _obj_##VAR.IsArray() ) {                                           \
 		JS_THROW("Argument " #I " must  be of type `Array`");                 \
+		RET_UNDEFINED;                                                        \
 	}                                                                         \
 	Napi::Array VAR = _obj_##VAR.As<Napi::Array>();
 
@@ -203,14 +207,11 @@
 	REQ_OBJ_ARG(I, _obj_##VAR);                                               \
 	if ( ! _obj_##VAR.IsTypedArray() ) {                                      \
 		JS_THROW("Argument " #I " must be of type `TypedArray`");             \
+		RET_UNDEFINED;                                                        \
 	}                                                                         \
 	Napi::TypedArray VAR = _obj_##VAR.As<Napi::TypedArray>();
 
 
-#define CTOR_CHECK(T)                                                         \
-	if ( ! info.IsConstructCall() )                                           \
-		JS_THROW(T " must be called with the 'new' keyword.");
-
 #define DES_CHECK                                                             \
 	if (_isDestroyed) return;
 
@@ -220,17 +221,15 @@
 
 #define CACHE_CAS(CACHE, V)                                                   \
 	if (CACHE == V) {                                                         \
-		return;                                                               \
+		RET_UNDEFINED;                                                        \
 	}                                                                         \
 	CACHE = V;
 
-#define THIS_SETTER_CHECK                                                     \
-	if (_isDestroyed) return;                                                 \
-	NAPI_ENV;
-
 #define SETTER_CHECK(C, T)                                                    \
-	if ( ! value.C )                                                          \
-		JS_THROW("Value must be " T);
+	if ( ! value.C ) {                                                        \
+		JS_THROW("Value must be " T);                                         \
+		RET_UNDEFINED;                                                        \
+	}
 
 
 #define JS_METHOD(NAME) Napi::Value NAME(const Napi::CallbackInfo &info)
@@ -335,7 +334,11 @@
 
 
 template<typename Type = uint8_t>
-inline Type* getArrayData(Napi::Env env, Napi::Object obj, int *num = nullptr) {
+inline Type* getArrayData(
+	Napi::Env env,
+	Napi::Object obj,
+	int *num = nullptr
+) {
 	
 	Type *data = nullptr;
 	
@@ -366,7 +369,11 @@ inline Type* getArrayData(Napi::Env env, Napi::Object obj, int *num = nullptr) {
 }
 
 template<typename Type = uint8_t>
-inline Type* getBufferData(Napi::Env env, Napi::Object obj, int *num = nullptr) {
+inline Type* getBufferData(
+	Napi::Env env,
+	Napi::Object obj,
+	int *num = nullptr
+) {
 	
 	Type *data = nullptr;
 	
@@ -410,7 +417,11 @@ inline void *getData(Napi::Env env, Napi::Object obj) {
 }
 
 
-inline void consoleLog(Napi::Env env, int argc, const Napi::Value *argv) {
+inline void consoleLog(
+	Napi::Env env,
+	int argc,
+	const Napi::Value *argv
+) {
 	JS_RUN_2("console.log", log);
 	std::vector<napi_value> args;
 	for (int i = 0; i < argc; i++) {
@@ -481,9 +492,17 @@ inline void eventEmitAsync(
 }
 
 
-inline void inheritEs5(napi_env env, Napi::Function ctor, Napi::Function superCtor) {
+inline void inheritEs5(
+	napi_env env,
+	Napi::Function ctor,
+	Napi::Function superCtor
+) {
 	
-	napi_value global, globalObject, setProto, ctorProtoProp, superCtorProtoProp;
+	napi_value global;
+	napi_value globalObject;
+	napi_value setProto;
+	napi_value ctorProtoProp;
+	napi_value superCtorProtoProp;
 	napi_value argv[2];
 	
 	napi_get_global(env, &global);
@@ -510,153 +529,170 @@ typedef Napi::Value (*Es5GetterCallback)(const Napi::CallbackInfo& info);
 typedef void (*Es5SetterCallback)(const Napi::CallbackInfo& info);
 
 
-#define DECLARE_ES5_CLASS(CLASS, NAME) \
-private: \
-	static Napi::FunctionReference _ctorEs5; \
-	static const char *_nameEs5; \
-	static void _finalizeEs5(napi_env e, void *dest, void* hint); \
-	static napi_value _createEs5(napi_env e, napi_callback_info i); \
-	inline void super( \
-		const Napi::CallbackInfo& info, \
-		int argc, \
-		const Napi::Value *argv \
-	) { \
-		Napi::Function ctor = _ctorEs5.Value(); \
-		if (ctor.Has("super_")) { \
-			Napi::Function _super = ctor.Get("super_").As<Napi::Function>(); \
-			std::vector<napi_value> args; \
-			for (int i = 0; i < argc; i++) { \
-				args.push_back(argv[i]); \
-			} \
-			_super.Call(info.This(), args); \
-		} \
-	} \
-	inline void super( \
-		const Napi::CallbackInfo& info, \
-		int argc = 0, \
-		const napi_value *argv = nullptr \
-	) { \
-		Napi::Function ctor = _ctorEs5.Value(); \
-		if (ctor.Has("super_")) { \
-			Napi::Function _super = ctor.Get("super_").As<Napi::Function>(); \
-			_super.Call(info.This(), argc, argv); \
-		} \
-	} \
-	inline static Napi::Function wrap(Napi::Env env) { \
-		napi_value __initResult; \
-		napi_create_function(env, #NAME, 0, _createEs5, nullptr, &__initResult); \
-		Napi::Function ctor = Napi::Function(env, __initResult); \
-		_ctorEs5 = Napi::Persistent(ctor); \
-		_ctorEs5.SuppressDestruct(); \
-		return ctor; \
-	} \
-	inline static Napi::Function wrap( \
-		Napi::Env env, \
-		Napi::Function superCtor \
-	) { \
-		Napi::Function ctor = wrap(env); \
-		inheritEs5(env, ctor, superCtor); \
-		return ctor; \
-	} \
-	inline static void method( \
-		const char *name, \
-		Es5MethodCallback cb \
-	) { \
-		Napi::Function proto = _ctorEs5.Value().Get("prototype").As<Napi::Function>(); \
-		proto.DefineProperty(                                                   \
-			Napi::PropertyDescriptor::Function(proto.Env(), proto, name, cb)   \
-		); \
-	} \
-	inline static void accessorR( \
-		const char *name, \
-		Es5GetterCallback getter \
-	) { \
-		Napi::Function proto = _ctorEs5.Value().Get("prototype").As<Napi::Function>(); \
-		proto.DefineProperty(                                                   \
-			Napi::PropertyDescriptor::Accessor(proto.Env(), proto, name, getter)   \
-		); \
-	} \
-	inline static void accessorRw( \
-		const char *name, \
-		Es5GetterCallback getter, \
-		Es5SetterCallback setter \
-	) { \
-		Napi::Function proto = _ctorEs5.Value().Get("prototype").As<Napi::Function>(); \
-		proto.DefineProperty(                                                   \
-			Napi::PropertyDescriptor::Accessor( \
-				proto.Env(), \
-				proto, \
-				name, \
-				getter, \
-				setter \
-			)   \
-		); \
-	} \
-public: \
-	inline static CLASS *unwrap(Napi::Object thatObj) { \
-		CLASS *that; \
-		napi_unwrap( \
-			thatObj.Env(), \
-			thatObj.Get(_nameEs5), \
-			reinterpret_cast<void**>(&that) \
-		); \
-		return that; \
+#define DECLARE_ES5_CLASS(CLASS, NAME)                                        \
+public:                                                                       \
+	inline static CLASS *unwrap(Napi::Object thatObj) {                       \
+		CLASS *that;                                                          \
+		napi_unwrap(                                                          \
+			thatObj.Env(),                                                    \
+			thatObj.Get(_nameEs5),                                            \
+			reinterpret_cast<void**>(&that)                                   \
+		);                                                                    \
+		return that;                                                          \
+	}                                                                         \
+private:                                                                      \
+	static Napi::FunctionReference _ctorEs5;                                  \
+	static const char *_nameEs5;                                              \
+	static void _finalizeEs5(napi_env e, void *dest, void* hint);             \
+	static napi_value _createEs5(napi_env e, napi_callback_info i);           \
+	inline void super(                                                        \
+		const Napi::CallbackInfo& info,                                       \
+		int argc,                                                             \
+		const Napi::Value *argv                                               \
+	) {                                                                       \
+		Napi::Function ctor = _ctorEs5.Value();                               \
+		if (ctor.Has("super_")) {                                             \
+			Napi::Function _super = ctor.Get("super_").As<Napi::Function>();  \
+			std::vector<napi_value> args;                                     \
+			for (int i = 0; i < argc; i++) {                                  \
+				args.push_back(argv[i]);                                      \
+			}                                                                 \
+			_super.Call(info.This(), args);                                   \
+		}                                                                     \
+	}                                                                         \
+	inline void super(                                                        \
+		const Napi::CallbackInfo& info,                                       \
+		int argc = 0,                                                         \
+		const napi_value *argv = nullptr                                      \
+	) {                                                                       \
+		Napi::Function ctor = _ctorEs5.Value();                               \
+		if (ctor.Has("super_")) {                                             \
+			Napi::Function _super = ctor.Get("super_").As<Napi::Function>();  \
+			_super.Call(info.This(), argc, argv);                             \
+		}                                                                     \
+	}                                                                         \
+	inline static Napi::Function wrap(Napi::Env env) {                        \
+		napi_value __initResult;                                              \
+		napi_create_function(                                                 \
+			env, #NAME, 0, _createEs5, nullptr, &__initResult                 \
+		);                                                                    \
+		Napi::Function ctor = Napi::Function(env, __initResult);              \
+		_ctorEs5 = Napi::Persistent(ctor);                                    \
+		_ctorEs5.SuppressDestruct();                                          \
+		return ctor;                                                          \
+	}                                                                         \
+	inline static Napi::Function wrap(                                        \
+		Napi::Env env,                                                        \
+		Napi::Function superCtor                                              \
+	) {                                                                       \
+		Napi::Function ctor = wrap(env);                                      \
+		inheritEs5(env, ctor, superCtor);                                     \
+		return ctor;                                                          \
+	}                                                                         \
+	inline static void method(                                                \
+		const char *name,                                                     \
+		Es5MethodCallback cb                                                  \
+	) {                                                                       \
+		Napi::Function proto = (                                              \
+			_ctorEs5.Value().Get("prototype").As<Napi::Function>()            \
+		);                                                                    \
+		proto.DefineProperty(                                                 \
+			Napi::PropertyDescriptor::Function(                               \
+				proto.Env(), proto, name, cb                                  \
+			)                                                                 \
+		);                                                                    \
+	}                                                                         \
+	inline static void accessorR(                                             \
+		const char *name,                                                     \
+		Es5GetterCallback getter                                              \
+	) {                                                                       \
+		Napi::Function proto = (                                              \
+			_ctorEs5.Value().Get("prototype").As<Napi::Function>()            \
+		);                                                                    \
+		proto.DefineProperty(                                                 \
+			Napi::PropertyDescriptor::Accessor(                               \
+				proto.Env(), proto, name, getter                              \
+			)                                                                 \
+		);                                                                    \
+	}                                                                         \
+	inline static void accessorRw(                                            \
+		const char *name,                                                     \
+		Es5GetterCallback getter,                                             \
+		Es5SetterCallback setter                                              \
+	) {                                                                       \
+		Napi::Function proto = (                                              \
+			_ctorEs5.Value().Get("prototype").As<Napi::Function>()            \
+		);                                                                    \
+		proto.DefineProperty(                                                 \
+			Napi::PropertyDescriptor::Accessor(                               \
+				proto.Env(),                                                  \
+				proto,                                                        \
+				name,                                                         \
+				getter,                                                       \
+				setter                                                        \
+			)                                                                 \
+		);                                                                    \
 	}
 
 
-#define JS_GET_THAT(CLASS) \
-	CLASS *that; \
-	Napi::Object thatObj = info.This().As<Napi::Object>(); \
-	napi_unwrap(info.Env(), thatObj.Get(_nameEs5), reinterpret_cast<void**>(&that));
+#define JS_GET_THAT(CLASS)                                                    \
+	CLASS *that;                                                              \
+	Napi::Object thatObj = info.This().As<Napi::Object>();                    \
+	napi_unwrap(                                                              \
+		info.Env(), thatObj.Get(_nameEs5), reinterpret_cast<void**>(&that)    \
+	);
 
-#define JS_DECLARE_METHOD(CLASS, NAME) \
-	inline static Napi::Value __st_##NAME(const Napi::CallbackInfo &info) { \
-		JS_GET_THAT(CLASS); \
-		return that->__i_##NAME(info); \
-	}; \
+#define JS_DECLARE_METHOD(CLASS, NAME)                                        \
+	inline static Napi::Value __st_##NAME(const Napi::CallbackInfo &info) {   \
+		JS_GET_THAT(CLASS);                                                   \
+		return that->__i_##NAME(info);                                        \
+	};                                                                        \
 	Napi::Value __i_##NAME(const Napi::CallbackInfo &info);
 
 #define JS_DECLARE_GETTER(CLASS, NAME) JS_DECLARE_METHOD(CLASS, NAME##Getter)
 
-#define JS_DECLARE_SETTER(CLASS, NAME)                                                       \
-	inline static void __st_##NAME##Setter( \
-		const Napi::CallbackInfo &info \
-	) { \
-		JS_GET_THAT(CLASS); \
-		that->__i_##NAME##Setter(info, info[0]); \
-	} \
-	void __i_##NAME##Setter(const Napi::CallbackInfo &info, const Napi::Value &value);
+#define JS_DECLARE_SETTER(CLASS, NAME)                                        \
+	inline static void __st_##NAME##Setter(                                   \
+		const Napi::CallbackInfo &info                                        \
+	) {                                                                       \
+		JS_GET_THAT(CLASS);                                                   \
+		that->__i_##NAME##Setter(info, info[0]);                              \
+	}                                                                         \
+	Napi::Value __i_##NAME##Setter(                                           \
+		const Napi::CallbackInfo &info,                                       \
+		const Napi::Value &value                                              \
+	);
 
-#define JS_IMPLEMENT_METHOD(CLASS, NAME) \
+#define JS_IMPLEMENT_METHOD(CLASS, NAME)                                      \
 	Napi::Value CLASS::__i_##NAME(const Napi::CallbackInfo &info)
 
 #define JS_IMPLEMENT_GETTER(CLASS, NAME) JS_IMPLEMENT_METHOD(CLASS, NAME##Getter)
 
-#define JS_IMPLEMENT_SETTER(CLASS, NAME) \
-	void CLASS::__i_##NAME##Setter( \
-		const Napi::CallbackInfo &info, \
-		const Napi::Value &value \
+#define JS_IMPLEMENT_SETTER(CLASS, NAME)                                      \
+	Napi::Value CLASS::__i_##NAME##Setter(                                    \
+		const Napi::CallbackInfo &info,                                       \
+		const Napi::Value &value                                              \
 	)
 
 #define JS_ASSIGN_METHOD(NAME) method(#NAME, __st_##NAME)
 #define JS_ASSIGN_GETTER(NAME) accessorR(#NAME, __st_##NAME##Getter)
-#define JS_ASSIGN_SETTER(NAME) accessorRw(#NAME, __st_##NAME##Getter, __st_##NAME##Setter)
+#define JS_ASSIGN_SETTER(NAME)                                                \
+	accessorRw(#NAME, __st_##NAME##Getter, __st_##NAME##Setter)
 
-#define IMPLEMENT_ES5_CLASS(CLASS) \
-	Napi::FunctionReference CLASS::_ctorEs5; \
-	const char *CLASS::_nameEs5 = #CLASS; \
-	void CLASS::_finalizeEs5(napi_env e, void *dest, void* hint) { \
-		CLASS *instance = reinterpret_cast<CLASS*>(dest); \
-		delete instance; \
-	} \
-	napi_value CLASS::_createEs5(napi_env env, napi_callback_info i) { \
-		Napi::CallbackInfo info(env, i); \
-		CLASS *instance = new CLASS(info); \
-		Napi::Object wrapObj = Napi::Object::New(env); \
-		info.This().As<Napi::Object>().Set(_nameEs5, wrapObj); \
-		napi_wrap(env, wrapObj, instance, _finalizeEs5, nullptr, nullptr); \
-		return info.Env().Undefined(); \
+#define IMPLEMENT_ES5_CLASS(CLASS)                                            \
+	Napi::FunctionReference CLASS::_ctorEs5;                                  \
+	const char *CLASS::_nameEs5 = #CLASS;                                     \
+	void CLASS::_finalizeEs5(napi_env e, void *dest, void* hint) {            \
+		CLASS *instance = reinterpret_cast<CLASS*>(dest);                     \
+		delete instance;                                                      \
+	}                                                                         \
+	napi_value CLASS::_createEs5(napi_env env, napi_callback_info i) {        \
+		Napi::CallbackInfo info(env, i);                                      \
+		CLASS *instance = new CLASS(info);                                    \
+		Napi::Object wrapObj = Napi::Object::New(env);                        \
+		info.This().As<Napi::Object>().Set(_nameEs5, wrapObj);                \
+		napi_wrap(env, wrapObj, instance, _finalizeEs5, nullptr, nullptr);    \
+		return info.Env().Undefined();                                        \
 	}
 
-
-#endif // _ADDON_TOOLS_HPP_
+#endif // ADDON_TOOLS_HPP