[beast: 1/70] Squash 'external/v8pp' content from commit f221bc9d099b



commit 3350665f20f1c56eaab772a6cce3538bbe008130
Author: Tim Janik <timj gnu org>
Date:   Fri Mar 24 09:40:13 2017 +0100

    Squash 'external/v8pp' content from commit f221bc9d099b
    
    git-subtree-dir: external/v8pp
    git-subtree-split: f221bc9d099b3088b7aa5cc580e46302e00304fd
    git-subtree-repo: http://github.com/tim-janik/v8pp

 .gitignore                                      |   14 +
 .travis.yml                                     |   25 +
 COPYING                                         |    4 +
 Doxyfile                                        | 2381 +++++++++++++++++++++++
 LICENSE_1_0.txt                                 |   23 +
 Makefile                                        |   31 +
 README.md                                       |  355 ++++
 build-v8.bat                                    |   34 +
 build-v8.sh                                     |   20 +
 build.ninja                                     |   42 +
 common.props                                    |   17 +
 docs/addons.md                                  |   47 +
 docs/config.md                                  |   22 +
 docs/context.md                                 |   16 +
 docs/convert.md                                 |  275 +++
 docs/exceptions.md                              |   22 +
 docs/index.md                                   |   18 +
 docs/persistent.md                              |    8 +
 docs/plugins.md                                 |   28 +
 docs/utilities.md                               |  110 ++
 docs/wrapping.md                                |  204 ++
 examples/01 hello world/binding.gyp             |   11 +
 examples/01 hello world/hello.cc                |   24 +
 examples/01 hello world/hello.js                |   11 +
 examples/02 arguments/addon.cc                  |   24 +
 examples/02 arguments/binding.gyp               |   11 +
 examples/02 arguments/test.js                   |   11 +
 examples/03 callbacks/addon.cc                  |   28 +
 examples/03 callbacks/binding.gyp               |   11 +
 examples/03 callbacks/test.js                   |   13 +
 examples/04 object factory/addon.cc             |   30 +
 examples/04 object factory/binding.gyp          |   11 +
 examples/04 object factory/test.js              |   13 +
 examples/05 function factory/addon.cc           |   35 +
 examples/05 function factory/binding.gyp        |   11 +
 examples/05 function factory/test.js            |   12 +
 examples/06 wrapped objects/addon.cc            |   18 +
 examples/06 wrapped objects/binding.gyp         |   11 +
 examples/06 wrapped objects/myobject.cc         |   45 +
 examples/06 wrapped objects/myobject.h          |   25 +
 examples/06 wrapped objects/test.js             |   14 +
 examples/07 wrapped objects factory/addon.cc    |   34 +
 examples/07 wrapped objects factory/binding.gyp |   12 +
 examples/07 wrapped objects factory/myobject.cc |   37 +
 examples/07 wrapped objects factory/myobject.h  |   25 +
 examples/07 wrapped objects factory/test.js     |   19 +
 examples/08 passing wrapped objects/addon.cc    |   44 +
 examples/08 passing wrapped objects/binding.gyp |   13 +
 examples/08 passing wrapped objects/myobject.cc |   16 +
 examples/08 passing wrapped objects/myobject.h  |   24 +
 examples/08 passing wrapped objects/test.js     |   15 +
 fetch-v8.py                                     |   32 +
 include_dirs.js                                 |    1 +
 package.json                                    |   15 +
 plugins/console.cpp                             |   40 +
 plugins/console.vcxproj                         |  175 ++
 plugins/console.vcxproj.filters                 |    9 +
 plugins/file.cpp                                |  147 ++
 plugins/file.vcxproj                            |  175 ++
 plugins/file.vcxproj.filters                    |    9 +
 plugins/packages.config                         |    9 +
 test/console.js                                 |   26 +
 test/file.js                                    |   48 +
 test/main.cpp                                   |  146 ++
 test/packages.config                            |    9 +
 test/test.hpp                                   |  126 ++
 test/test.vcxproj                               |  187 ++
 test/test.vcxproj.filters                       |   25 +
 test/test_call_from_v8.cpp                      |   80 +
 test/test_call_v8.cpp                           |   35 +
 test/test_class.cpp                             |  177 ++
 test/test_context.cpp                           |   20 +
 test/test_convert.cpp                           |  174 ++
 test/test_factory.cpp                           |  117 ++
 test/test_function.cpp                          |   54 +
 test/test_json.cpp                              |   56 +
 test/test_module.cpp                            |   71 +
 test/test_object.cpp                            |   53 +
 test/test_property.cpp                          |  109 +
 test/test_throw_ex.cpp                          |   41 +
 test/test_utility.cpp                           |  218 +++
 v8_options.gypi                                 |   20 +
 v8pp.sln                                        |   62 +
 v8pp/call_from_v8.hpp                           |  185 ++
 v8pp/call_v8.hpp                                |   43 +
 v8pp/class.hpp                                  |  773 ++++++++
 v8pp/config.hpp                                 |   45 +
 v8pp/context.cpp                                |  267 +++
 v8pp/context.hpp                                |   86 +
 v8pp/convert.hpp                                |  685 +++++++
 v8pp/factory.hpp                                |   43 +
 v8pp/function.hpp                               |  220 +++
 v8pp/json.hpp                                   |   70 +
 v8pp/module.hpp                                 |  167 ++
 v8pp/object.hpp                                 |   75 +
 v8pp/packages.config                            |    9 +
 v8pp/persistent.hpp                             |  170 ++
 v8pp/property.hpp                               |  400 ++++
 v8pp/throw_ex.hpp                               |   53 +
 v8pp/utility.hpp                                |  294 +++
 v8pp/v8pp.vcxproj                               |  172 ++
 v8pp/v8pp.vcxproj.filters                       |   25 +
 102 files changed, 10552 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fd46ae5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+/bin
+/docs/html
+/docs/xml
+/node_modules
+/packages
+/.vs
+/*.*sdf
+/*.suo
+/*.VC.db
+*.user
+*.exe
+*.so
+*.o
+*.a
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8e2eb89
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,25 @@
+language: c++
+
+sudo: required
+dist: trusty
+
+compiler:
+  - gcc
+  - clang
+
+env: 
+  - V8_VERSION=4.10
+  - V8_VERSION=5.2
+  - V8_VERSION=5.4
+
+before_install:
+  - sudo add-apt-repository ppa:pinepain/libv8-"$V8_VERSION" -y
+  - sudo apt-get update -q
+  - sudo apt-get install libv8-"$V8_VERSION"-dev -y
+
+install:
+  - if [ "$CXX" == "clang++" ]; then export CXXFLAGS="-stdlib=libstdc++"; fi
+  
+script: make
+
+after_success: LD_LIBRARY_PATH=. ./v8pp_test -v --run-tests test/console.js test/file.js
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..4039fe4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,4 @@
+Copyright (c) 2013-2015 Pavel Medvedev (pmedvedev at gmail dot com)
+
+Distributed under the Boost Software License, Version 1.0. (See accompanying
+file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..dc1fa54
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2381 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "v8pp"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = 1.0.0
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Bind C++ code into V8 JavaScript engine"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = v8pp/ README.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           = plugins/console.cpp plugins/file.cpp 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c7998a8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,31 @@
+CXX ?= c++
+CXXFLAGS += -Wall -Wextra -std=c++11 -fPIC -DV8PP_ISOLATE_DATA_SLOT=0
+LDFLAGS += -shared
+AR = ar
+ARFLAGS = rcs
+
+INCLUDES = -I. -I./v8pp -isystem./v8/include -isystem./v8 -isystem/usr -isystem/usr/lib
+LIBS = -L./v8/lib -lv8 -lv8_libplatform -lv8_base -lv8_libbase -licui18n -licuuc -L. -lv8pp -ldl -lpthread
+
+.cpp.o:
+       $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
+
+all: lib plugins v8pp_test
+
+v8pp_test: $(patsubst %.cpp, %.o, $(wildcard test/*.cpp))
+       $(CXX) $^ -o $@ $(LIBS)
+
+lib: $(patsubst %.cpp, %.o, $(wildcard v8pp/*.cpp))
+       $(AR) $(ARFLAGS) libv8pp.a $^
+
+plugins: console file
+
+console: $(patsubst %.cpp, %.o, plugins/console.cpp)
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) $(LIBS) $^ -o $@.so
+
+file: $(patsubst %.cpp, %.o, plugins/file.cpp)
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) $(LIBS) $^ -o $@.so
+
+clean:
+       rm -rf v8pp/*.o test/*.o plugins/*.o libv8pp.a v8pp_test console.so file.so
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..39bfcdb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,355 @@
+[![Travis Build status](https://travis-ci.org/pmed/v8pp.svg)](https://travis-ci.org/pmed/v8pp)
+[![AppVeyor build 
status](https://ci.appveyor.com/api/projects/status/github/pmed/v8pp?svg=true)](https://ci.appveyor.com/project/pmed/v8pp)
+[![NPM](https://img.shields.io/npm/v/v8pp.svg)](https://npmjs.com/package/v8pp)
+[![Join the chat at 
https://gitter.im/pmed/v8pp](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/pmed/v8pp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+# v8pp
+
+Header-only library to expose C++ classes and functions into [V8](https://developers.google.com/v8/) to use 
them in JavaScript code. v8pp uses heavy template metaprogramming and variadic template parameters which 
requires modern compiler with C++11 support. The library has been tested on:
+
+  * Microsoft Visual C++ 2013 (Windows 7/8)
+  * GCC 4.8.1 (Ubuntu 13.10 with Linux kernel 3.11.0)
+  * Clang 3.5 (Mac OS X 10.2)
+
+## Binding example
+
+v8pp supports V8 versions after 3.21 with `v8::Isolate` usage in API. There are 2 targets for binding:
+ 
+  * `v8pp::module`, a wrapper class around `v8::ObjectTemplate`
+  * `v8pp::class_`, a template class wrapper around `v8::FunctionTemplate`
+
+Both of them require a pointer to `v8::Isolate` instance. They allows to bind from C++ code such items as 
variables, functions, constants with a function `set(name, item)`:
+
+```c++
+v8::Isolate* isolate;
+
+int var;
+int get_var() { return var + 1; }
+void set_var(int x) { var = x + 1; }
+
+struct X
+{
+       X(int v, bool u) : var(v) {}
+       int var;
+       int get() const { return var; }
+       voi set(int x) { var = x; } 
+};
+
+// bind free variables and functions
+v8pp::module mylib(isolate);
+mylib
+    // set read-only attribute
+    .set_const("PI", 3.1415)
+       // set variable available in JavaScript with name `var`
+       .set("var", var)
+       // set function get_var as `fun`
+       .set("fun", &get_var)
+       // set property `prop` with getter get_var() and setter set_var()
+    .set("prop", property(get_var, set_var));
+
+// bind class
+v8pp::class_<X> X_class(isolate);
+X_class
+       // specify X constructor signature
+       .ctor<int, bool>()
+       // bind variable
+       .set("var", &X::var)
+       // bind function
+       .set("fun", &X::set)
+       // bind read-only property
+       .set("prop", property(&X::get));
+
+// set class into the module template
+mylib.set("X", X_class);
+
+// set bindings in global object as `mylib`
+isolate->GetCurrentContext()->Global()->Set(
+       v8::String::NewFromUtf8(isolate, "mylib"), mylib.new_instance());
+```
+
+After that bindings will be available in JavaScript:
+```javascript
+mylib.var = mylib.PI + mylib.fun();
+var x = new mylib.X(1, true);
+mylib.prop = x.prop + x.fun();
+```
+
+## Node.js and io.js addons
+
+The library is suitable to make [Node.js](http://nodejs.org/) and [io.js](https://iojs.org/) addons. See 
[addons](docs/addons.md) document.
+
+```c++
+
+void RegisterModule(v8::Handle<v8::Object> exports)
+{
+       v8pp::module addon(v8::Isolate::GetCurrent());
+
+       // set bindings... 
+       addon
+               .set("fun", &function)
+               .set("cls", my_class)
+               ;
+
+       // set bindings as exports object prototype
+       exports->SetPrototype(addon.new_instance());
+}
+```
+
+## v8pp also provides
+
+* `v8pp` - a static library to add several global functions (load/require to the v8 JavaScript context. 
`require()` is a system for loading plugins from shared libraries.
+* `test` - A binary for running JavaScript files in a context which has v8pp module loading functions 
provided.
+
+## v8pp module example
+
+```c++
+#include <iostream>
+
+#include <v8pp/module.hpp>
+
+namespace console {
+
+void log(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       v8::HandleScope handle_scope(args.GetIsolate());
+
+       for (int i = 0; i < args.Length(); ++i)
+       {
+               if (i > 0) std::cout << ' ';
+               v8::String::Utf8Value str(args[i]);
+               std::cout <<  *str;
+       }
+       std::cout << std::endl;
+}
+
+v8::Handle<v8::Value> init(v8::Isolate* isolate)
+{
+       v8pp::module m(isolate);
+       m.set("log", &log);
+       return m.new_instance();
+}
+
+} // namespace console
+```
+
+## Turning a v8pp module into a v8pp plugin
+
+```c++
+V8PP_PLUGIN_INIT(v8::Isolate* isolate)
+{
+       return console::init(isolate);
+}
+```
+
+## v8pp class binding example
+
+```c++
+#include <v8pp/module.hpp>
+#include <v8pp/class.hpp>
+
+#include <fstream>
+
+namespace file {
+
+bool rename(char const* src, char const* dest)
+{
+       return std::rename(src, dest) == 0;
+}
+
+class file_base
+{
+public:
+       bool is_open() const { return stream_.is_open(); }
+       bool good() const { return stream_.good(); }
+       bool eof() const { return stream_.eof(); }
+       void close() { stream_.close(); }
+
+protected:
+       std::fstream stream_;
+};
+
+class file_writer : public file_base
+{
+public:
+       explicit file_writer(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               if (args.Length() == 1)
+               {
+                       v8::String::Utf8Value str(args[0]);
+                       open(*str);
+               }
+       }
+
+       bool open(char const* path)
+       {
+               stream_.open(path, std::ios_base::out);
+               return stream_.good();
+       }
+
+       void print(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               v8::HandleScope scope(args.GetIsolate());
+
+               for (int i = 0; i < args.Length(); ++i)
+               {
+                       if (i > 0) stream_ << ' ';
+                       v8::String::Utf8Value str(args[i]);
+                       stream_ << *str;
+               }
+       }
+
+       void println(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               print(args);
+               stream_ << std::endl;
+       }
+};
+
+class file_reader : public file_base
+{
+public:
+       explicit file_reader(char const* path)
+       {
+               open(path);
+       }
+
+       bool open(const char* path)
+       {
+               stream_.open(path, std::ios_base::in);
+               return stream_.good();
+       }
+
+       v8::Handle<v8::Value> getline(v8::Isolate* isolate)
+       {
+               if ( stream_.good() && ! stream_.eof())
+               {
+                       std::string line;
+                       std::getline(stream_, line);
+                       return v8pp::to_v8(isolate, line);
+               }
+               else
+               {
+                       return v8::Undefined(isolate);
+               }
+       }
+};
+
+v8::Handle<v8::Value> init(v8::Isolate* isolate)
+{
+       v8::EscapableHandleScope scope(isolate);
+
+       // file_base binding, no .ctor() specified, object creation disallowed in JavaScript
+       v8pp::class_<file_base> file_base_class(isolate);
+       file_base_class
+               .set("close", &file_base::close)
+               .set("good", &file_base::good)
+               .set("is_open", &file_base::is_open)
+               .set("eof", &file_base::eof)
+               ;
+
+       // .ctor<> template arguments declares types of file_writer constructor
+       // file_writer inherits from file_base_class
+       v8pp::class_<file_writer> file_writer_class(isolate);
+       file_writer_class
+               .ctor<v8::FunctionCallbackInfo<v8::Value> const&>()
+               .inherit<file_base>()
+               .set("open", &file_writer::open)
+               .set("print", &file_writer::print)
+               .set("println", &file_writer::println)
+               ;
+
+       // .ctor<> template arguments declares types of file_reader constructor.
+       // file_base inherits from file_base_class
+       v8pp::class_<file_reader> file_reader_class(isolate);
+       file_reader_class
+               .ctor<char const*>()
+               .inherit<file_base>()
+               .set("open", &file_reader::open)
+               .set("getln", &file_reader::getline)
+               ;
+
+       // Create a module to add classes and functions to and return a
+       // new instance of the module to be embedded into the v8 context
+       v8pp::module m(isolate);
+       m.set("rename", &rename)
+        .set("writer", file_writer_class)
+        .set("reader", file_reader_class)
+               ;
+
+       return scope.Escape(m.new_instance());
+}
+
+} // namespace file
+
+V8PP_PLUGIN_INIT(v8::Isolate* isolate)
+{
+       return file::init(isolate);
+}
+```
+
+## Creating a v8 context capable of using require() function
+
+```c++
+#include <v8pp/context.hpp>
+
+v8pp::context context;
+context.set_lib_path("path/to/plugins/lib");
+// script can now use require() function. An application
+// that uses v8pp::context must link against v8pp library.
+v8::HandleScope scope(context.isolate());
+context.run_file("some_file.js");
+```
+
+## Using require() from JavaScript
+
+```javascript
+// Load the file module from the class binding example and the
+// console module.
+var file    = require('file'),
+    console = require('console')
+
+var writer = new file.writer("file")
+if (writer.is_open()) {
+    writer.println("some text")
+    writer.close()
+    if (! file.rename("file", "newfile"))
+        console.log("could not rename file")
+}
+else console.log("could not open `file'")
+
+console.log("exit")
+```
+
+## Create a handle to an externally referenced C++ class.
+
+```c++
+// Memory for C++ class will remain when JavaScript object is deleted.
+// Useful for classes you only wish to inject.
+typedef v8pp::class_<my_class> my_class_wrapper(isolate);
+v8::Handle<v8::Value> val = my_class_wrapper::reference_external(&my_class::instance());
+// Assuming my_class::instance() returns reference to class
+```
+
+## Import externally created C++ class into v8pp.
+
+```c++
+// Memory for c++ object will be reclaimed by JavaScript using "delete" when
+// JavaScript class is deleted.
+typedef v8pp::class_<my_class> my_class_wrapper(isolate);
+v8::Handle<v8::Value> val = my_class_wrapper::import_external(new my_class);
+```
+
+## Compile-time configuration
+
+The library uses several preprocessor macros, defined in `v8pp/config.hpp` file:
+
+  * `V8PP_ISOLATE_DATA_SLOT` - A v8::Isolate data slot number, used to store v8pp internal data
+  * `V8PP_PLUGIN_INIT_PROC_NAME` - Plugin initialization procedure name that should be exported from a v8pp 
plugin.
+  * `V8PP_PLUGIN_SUFFIX` - Plugin filename suffix that would be added if the plugin name used in `require()` 
doesn't end with it.
+
+## v8pp alternatives
+
+* [nbind](https://github.com/charto/nbind)
+* [vu8](https://github.com/tsa/vu8), abandoned
+* [v8-juice](http://code.google.com/p/v8-juice/), abandoned
+* Script bindng in [cpgf](https://github.com/cpgf/cpgf)
diff --git a/build-v8.bat b/build-v8.bat
new file mode 100644
index 0000000..a3f6f59
--- /dev/null
+++ b/build-v8.bat
@@ -0,0 +1,34 @@
+rem Run this batch file in a Visual Studio command prompt. After the batch file has been executed, build 
v8pp with:
+rem msbuild /p:Configuration=Release /p:Platform=x64 v8pp.sln
+
+rem Fetch V8 and dependencies
+python fetch-v8.py
+pushd v8
+
+rem Generate project files
+python tools\gyp\gyp_main.py -fmsvs -Dtarget_arch=x64 --depth=. -I./gypfiles/standalone.gypi 
-I../v8_options.gypi src\v8.gyp
+
+rem Build
+
+:Release
+msbuild /m /p:Configuration=Release /p:Platform=x64 src\v8.sln
+mkdir lib\x64\Release
+copy build\Release\lib\*.lib lib\x64\Release
+copy build\Release\lib\*.exp lib\x64\Release
+copy build\Release\v8_lib*.lib lib\x64\Release
+copy build\Release\*.dll lib\x64\Release
+copy build\Release\*.pdb lib\x64\Release
+
+goto done
+
+:Debug
+msbuild /m /p:Configuration=Debug /p:Platform=x64 src\v8.sln
+mkdir lib\x64\Debug
+copy build\Debug\lib\*.lib lib\x64\Debug
+copy build\Debug\lib\*.exp lib\x64\Debug
+copy build\Debug\v8_lib*.lib lib\x64\Debug
+copy build\Debug\*.dll lib\x64\Debug
+copy build\Debug\*.pdb lib\x64\Debug
+
+:done
+popd
\ No newline at end of file
diff --git a/build-v8.sh b/build-v8.sh
new file mode 100755
index 0000000..a562812
--- /dev/null
+++ b/build-v8.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env sh
+
+git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
+export PATH=`pwd`/depot_tools:"$PATH"
+fetch --no-history v8
+cd v8
+gclient sync
+
+GYP_DIR=build
+if [ ! -f "$GYP_DIR"/gyp_v8 ] ; then
+  GYP_DIR=gypfiles
+fi
+
+GYP_GENERATORS=make "$GYP_DIR"/gyp_v8 --generator-output=out --depth=. -I"$GYP_DIR"/standalone.gypi 
-I../v8_options.gypi "$GYP_DIR"/all.gyp
+make v8 v8_libplatform -C out BUILDTYPE=Release -j8 builddir=$(pwd)/out/Release
+mkdir -p lib
+cp out/Release/lib.target/*.so lib
+cp out/Release/lib* lib
+cd ..
+
diff --git a/build.ninja b/build.ninja
new file mode 100644
index 0000000..b5ca4a6
--- /dev/null
+++ b/build.ninja
@@ -0,0 +1,42 @@
+cxx = c++
+cxxflags = -Wall -Wextra -Wno-return-type-c-linkage -std=c++11 -fPIC -I. -I./v8pp -isystem./v8/include 
-isystem./v8 -DV8PP_ISOLATE_DATA_SLOT=0
+ldflags = -L./v8/lib -lv8 -lv8_libplatform -lv8_base -lv8_libbase -licui18n  -licuuc -L. -lv8pp -ldl 
-lpthread
+
+rule cxx
+  command = $cxx $cxxflags -c $in -o $out
+  description = $cxx $in
+
+rule ar
+  command = ar rcs $out $in
+  description = ar $out
+
+rule link
+  command = $cxx -o $out $in $ldflags
+  description = link $out
+
+rule plugin
+  command = $cxx $cxxflags $in -o $out $ldflags -shared
+  description = plugin $out
+
+build v8pp_test: link test/main.o test/test_call_from_v8.o test/test_call_v8.o test/test_class.o 
test/test_context.o test/test_convert.o test/test_factory.o test/test_function.o test/test_json.o 
test/test_module.o test/test_object.o test/test_property.o test/test_throw_ex.o test/test_utility.o || 
libv8pp.a file.so console.so
+
+build libv8pp.a: ar v8pp/context.o
+build console.so: plugin plugins/console.cpp || libv8pp.a
+build file.so: plugin plugins/file.cpp || libv8pp.a
+
+build v8pp/context.o: cxx v8pp/context.cpp
+
+build test/main.o: cxx test/main.cpp
+build test/test_call_from_v8.o: cxx test/test_call_from_v8.cpp
+build test/test_call_v8.o: cxx test/test_call_v8.cpp
+build test/test_class.o: cxx test/test_class.cpp
+build test/test_context.o: cxx test/test_context.cpp
+build test/test_convert.o: cxx test/test_convert.cpp
+build test/test_factory.o: cxx test/test_factory.cpp
+build test/test_function.o: cxx test/test_function.cpp
+build test/test_json.o: cxx test/test_json.cpp
+build test/test_module.o: cxx test/test_module.cpp
+build test/test_object.o: cxx test/test_object.cpp
+build test/test_property.o: cxx test/test_property.cpp
+build test/test_throw_ex.o: cxx test/test_throw_ex.cpp
+build test/test_utility.o: cxx test/test_utility.cpp
diff --git a/common.props b/common.props
new file mode 100644
index 0000000..8f4aafc
--- /dev/null
+++ b/common.props
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup>
+    <OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
+    <IntDir>$(SolutionDir)bin\$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4190</DisableSpecificWarnings>
+      
<PreprocessorDefinitions>V8_USE_UNSAFE_HANDLES;V8_DISABLE_DEPRECATIONS;V8PP_ISOLATE_DATA_SLOT=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+  </ItemDefinitionGroup>
+</Project>
diff --git a/docs/addons.md b/docs/addons.md
new file mode 100644
index 0000000..79366cb
--- /dev/null
+++ b/docs/addons.md
@@ -0,0 +1,47 @@
+# Node.js addons
+
+The library allows to create native C++ addons for [Node.js](http://nodejs.org/)
+version 0.11 and above, and [io.js](https://iojs.org/) version 1.0.
+
+See [Addons documentation](http://nodejs.org/docs/v0.12.0/api/addons.html)
+for reference.
+
+Node.js native addons uses `node-gyp`(https://github.com/nodejs/node-gyp)
+build tool to make them with C++ compiler.
+
+This library is published as an NPM package: https://www.npmjs.com/package/v8pp
+and maybe used as an addon dependency in a way similar to NAN.
+
+To use `v8pp` in a native Node.js addon append it as a dependency in the addon
+`package.json` file:
+
+```json
+{
+       "dependencies": {
+               "v8pp": "^1.0"
+       }
+}
+```
+
+This library uses C++11 with RTTI and exceptions which should be enabled by overriding
+C++ compiler flags in `bindings.gyp` file:
+```
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'cflags_cc': ['-std=c++11', '-fexceptions', '-frtti'],
+                       'msvs_settings': { 'VCCLCompilerTool': { 'ExceptionHandling': 1, 'RuntimeTypeInfo': 
'true' } },
+                       'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',  'GCC_ENABLE_CPP_RTTI': 
'YES', },
+                       'defines!': ['V8_DEPRECATION_WARNINGS=1'],
+                       'include_dirs': [ '<!(node -e require(\'v8pp\'))'],
+                       'sources': ['hello.cc'],
+               }
+       ]
+}
+```
+
+Here is a side-by-side difference between Node and v8pp in amount of C++ code
+required to implement similar addons:
+https://github.com/pmed/v8pp/commit/34c6344bdb1bdf7f0b46db6ea15c8ddd20ac3824?diff=split
diff --git a/docs/config.md b/docs/config.md
new file mode 100644
index 0000000..67ddb69
--- /dev/null
+++ b/docs/config.md
@@ -0,0 +1,22 @@
+# Compile time configuration
+
+The library has a set of `#define` directives in
+[`v8pp/config.hpp`](../v8pp/config.hpp) header file to customize some options,
+mostly for [`plugins`](./plugins.md):
+
+  * `#define V8PP_ISOLATE_DATA_SLOT` - v8::Isolate data slot number internally
+    used by v8pp, see documentation for `v8::Isolate::GetNumberOfDataSlots()`,
+    `v8::Isolate::SetData()`, and `v8::Isolate::GetData()` functions.
+
+  * `#define V8PP_PLUGIN_INIT_PROC_NAME` - `v8pp` plugin initialization
+    procedure name.
+
+  * `#define V8PP_PLUGIN_SUFFIX` - default `v8pp` plugin filename suffix used
+    in `require(name)` implementation, `".dll"` on Windows platform, `".so"`
+    on others.
+
+  * `#define V8PP_EXPORT` and `#define V8PP_IMPORT` - platfrom-specific
+    defines for symbols export and import in loadable plugin modules.
+
+  * `#define V8PP_PLUGIN_INIT(isolate)` - a shortcurt delcaration for plugin
+    initialization function.
diff --git a/docs/context.md b/docs/context.md
new file mode 100644
index 0000000..e5b7528
--- /dev/null
+++ b/docs/context.md
@@ -0,0 +1,16 @@
+# Context
+
+File [`v8pp/context.hpp`](../v8pp/context.hpp) contains `v8pp::context` class
+that simplifies V8 embedding and maintains custom [plugins](plugins.md)
+registry.
+
+Constructor of `v8pp::context` class accepts a pointer to `v8::Isolate`
+instance (or creates a new one, if `nullptr` was supplied), creates a
+`v8::Context` and initializes the co global object with following functions:
+
+  * require(filename) - load a plugin module
+  * run(filename) - run a JavaScript file
+
+
+Context class also supports binding of C++ classes and functions into the
+global object similar to [`v8pp::module`](wrapping.md#v8pp::module)
\ No newline at end of file
diff --git a/docs/convert.md b/docs/convert.md
new file mode 100644
index 0000000..8937987
--- /dev/null
+++ b/docs/convert.md
@@ -0,0 +1,275 @@
+# Data conversion
+
+V8 has a set of classes for JavaScript types - `Object`, `Array`, `Number`, 
+and others. There is a `v8pp::convert` template to convert fundamental and
+user-defined C++ types from and to V8 JavaScript types in a header file
+[`v8pp/convert.hpp`](../v8pp/convert.hpp)
+
+Function template `v8pp::to_v8(v8::Isolate*, T const& value)` converts a C++
+value to a V8 Value instance:
+
+```c++
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+v8::Local<v8::Value>  v8_int = v8pp::to_v8(isolate, 42);
+v8::Local<v8::String> v8_str = v8pp::to_v8(isolate, "hello");
+```
+
+The opposite function template `v8pp::from_v8<T>(v8::Isolate*, v8::Handle<v8::Value> value)`
+converts a V8 value to a C++ value of explicitly declared type `T`.
+
+If source V8 value is empty or not convertible to the specified C++ type,
+a `std::invalid_argument` exception would be thrown.
+
+An overloaded function `v8pp::from_v8<T>(v8::Isolate*, v8::Handle<v8::Value>, T const& default_value)`
+converts a V8 value or returns `default_value` on conversion error.
+
+```c++
+auto i = v8pp::from_v8<int>(isolate, v8_int); // i == 42
+auto s = v8pp::from_v8<std::string>(isolate, v8_str); // s = "hello"
+
+v8pp::from_v8<int>(isolate, v8_str); // throws std::invalid_argument("expected Number")
+
+auto i2 = v8pp::from_v8<int>(isolate, v8_str, -1); // i2 == -1 
+```
+
+Currently v8pp allows following conversions:
+
+  * `bool` <-> `v8::Boolean`
+  * integral type (`short`, `int`, `long`, and unsigned) <-> `v8::Number`
+  * C++ `enum` <--> `v8::Number`
+  * floating point (`float`, `double`) <-> `v8::Number`
+  * string <-> `v8::String`
+  * `std::vector<T>` <-> `v8::Array`
+  * `std::map<Key, Value>` <-> `v8::Object`
+  * [wrapped](wrapping.md) C++ objects <-> `v8::Object`
+
+**Caution:** JavaScript has no distinct integer an floating types.
+It is unsafe to convert integer values greater than 2^53
+
+
+## Strings
+
+The library supports conversions for UTF-8 encoded `std::string`, UTF-16
+encoded `std::wstring`, zero-terminated C strings, and string literals with
+optional explicit length supplied:
+
+```c++
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+v8::Local<v8::String> v8_str1 = v8pp::to_v8(isolate, std::string("UTF-8 encoded std::string"));
+v8::Local<v8::String> v8_str2 = v8pp::to_v8(isolate, "UTF-8 encoded C-string");
+v8::Local<v8::String> v8_str3 = v8pp::to_v8(isolate, L"UTF-16 encoded string with optional explicit length", 
21);
+
+auto const str1 = v8pp::from_v8<std::string>(isolate, v8_str1);
+auto const str2 = v8pp::from_v8<char const*>(isolate, v8_str2); // a `std::string const&` instance, in fact
+auto const str3 = v8pp::from_v8<std::wstring>(isolate, v8_str3);
+```
+
+
+## Arrays and Objects
+
+There is a `v8pp::to_v8(v8::Isolate*, InputIterator begin, InputIterator end)`
+and `v8pp::to_v8(v8::Isolate* isolate, std::initializer_list<T> const& init)`
+function templates to convert a pair of input iterators or initializer list of
+elements to V8 `Array`:
+
+```c++
+std::list<std::string> container{ "a", "b", "c" };
+v8::Local<v8::Array> v8_arr = v8pp::to_v8(isolate, container.begin(), container.end());
+v8::Local<v8::Array> v8_arr2 = v8pp::to_v8(isolate, { 1, 2, 3 });
+
+auto arr = v8pp::from_v8<std::vector<std::string>>(isolate, v8_arr);
+auto arr2 = v8pp::from_v8<std::array<int, 3>>(isolate, v8_arr2);
+```
+
+The library allows conversion between `std::vector<T>` and `v8::Array` if
+type `T` is convertible.
+
+The similar is for `std::map<Key, Type>` and `v8::Object` for `Key` and
+`Value` types.
+
+```c++
+std::vector<int> vector{ 1, 2, 3 };
+v8::Local<v8::Array> v8_vector = v8pp::to_v8(isolate, vector);
+
+std::map<std::string, int> map{ { "a", 0 }, { "b", 1 } };
+v8::Local<v8::Object> v8_map = v8pp::to_v8(isolate, map);
+
+auto v = v8pp::from_v8<std::vector<int>>(isolate, v8_vector);
+auto m = v8pp::from_v8<std::map<std::string, int>>(isolate, v8_map);
+```
+
+## Wrapped C++ objects
+
+[Wrapped](wrapping.md) C++ objects can be converted by pointer or by reference:
+
+```c++
+class MyClass {};
+
+v8pp::class_<MyClass> bind_MyClass(isolate);
+
+v8::Local<v8::Object> obj = v8pp::class_<MyClass>::create_object(isolate);
+
+MyClass* ptr = v8pp::from_v8<MyClass*>(isolate, obj);
+MyClass& ref = v8pp::from_v8<MyClass&>(isolate, obj);
+
+MyClass* none = v8pp::from_v8<MyClass*>(isolate, v8::Null(isolate)); // none == nullptr
+MyClass& err = v8pp::from_v8<MyClass&>(isolate, v8::Object::New(isolate)); // throws 
std::runtime_error("expected C++ wrapped object")
+
+v8::Local<v8::Object> obj2 = v8pp::to_v8(isolate, ptr); // obj == obj2
+v8::Local<v8::Object> obj3 = v8pp::to_v8(isolate, ref); // obj == obj3
+
+// unwrapped C++ object converts to empty handle
+v8::Local<v8::Object> obj4 = v8pp::to_v8(isolate, new MyClass{}); // obj4.IsEmpty() == true
+```
+
+
+## User-defined types
+
+A `v8pp::convert` template may be specialized to allow conversion from/to
+V8 values for user defined types that have not been wrapped with `v8pp::class_`
+
+Such a specialization of `v8pp::convert` template should have following
+conversion functions:
+
+```c++
+// Generic convertor
+template<typename T>
+struct convert
+{
+    // C++ return type for v8pp::from_v8() function
+       using from_type = T;
+
+       // V8 return type for v8pp::to_v8() function
+       using to_type = v8::Handle<v8::Value>;
+
+       // Is V8 value valid to convert from?
+       static bool is_valid(v8::Isolate* isolate, v8::Handle<v8::Value> value);
+
+       // Convert V8 value to C++
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value);
+
+       // Convert C++ value to V8
+       static to_type to_v8(v8::Isolate* isolate, T const& value);
+};
+```
+
+Example for a user type:
+
+```c++
+struct Vector3
+{
+       float x, y, z;
+};
+
+// Explicit convertor template specialization
+template<>
+struct v8pp::convert<Vector3>
+{
+       using from_type = Vector3;
+       using to_type = v8::Handle<v8::Array>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsArray()
+                       && value.As<v8::Array>()->Length() == 3;
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected [x, y, z] array");
+               }
+
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Array> arr = value.As<v8::Array>();
+
+               from_type result;
+               result.x = v8pp::from_v8<float>(isolate, arr->Get(0));
+               result.y = v8pp::from_v8<float>(isolate, arr->Get(1));
+               result.z = v8pp::from_v8<float>(isolate, arr->Get(2));
+
+               return result;
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, Vector3 const& value)
+       {
+               v8::EscapableHandleScope scope(isolate);
+
+               v8::Local<v8::Array> arr = v8::Array::New(isolate, 3);
+               arr->Set(0, v8pp::to_v8(isolate, value.x));
+               arr->Set(1, v8pp::to_v8(isolate, value.y));
+               arr->Set(2, v8pp::to_v8(isolate, value.z));
+
+               return scope.Escape(arr);
+       }
+};
+
+v8::Local<v8::Array> vec3_js = v8pp::to_v8(isolate, Vector3{ 1, 2, 3 });
+Vector3 vec3 = v8pp::from_v8<Vector3>(isolate, vec3_js); // == { 1, 2, 3 }
+
+```
+
+
+User defined class template should also specialize `v8pp::is_wrapped_class`
+as `std::false_type` in order to disable conversion as a C++ wrapped
+with `v8pp::class_` type:
+
+```c++
+template<typename T>
+struct Vector3
+{
+       T x, y, z;
+};
+
+template<typename T>
+struct v8pp::convert<Vector3<T>>
+{
+       using from_type = Vector3<T>;
+       using to_type = v8::Handle<v8::Array>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsArray()
+                       && value.As<v8::Array>()->Length() == 3;
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected [x, y, z] array");
+               }
+
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Array> arr = value.As<v8::Array>();
+
+               from_type result;
+               result.x = v8pp::from_v8<T>(isolate, arr->Get(0));
+               result.y = v8pp::from_v8<T>(isolate, arr->Get(1));
+               result.z = v8pp::from_v8<T>(isolate, arr->Get(2));
+
+               return result;
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, Vector3<T> const& value)
+       {
+               v8::EscapableHandleScope scope(isolate);
+
+               v8::Local<v8::Array> arr = v8::Array::New(isolate, 3);
+               arr->Set(0, v8pp::to_v8(isolate, value.x));
+               arr->Set(1, v8pp::to_v8(isolate, value.y));
+               arr->Set(2, v8pp::to_v8(isolate, value.z));
+
+               return scope.Escape(arr);
+       }
+};
+
+template<typename T>
+struct v8pp::is_wrapped_class<Vector3<T>> : std::false_type{};
+
+v8::Local<v8::Array> vec3_js = v8pp::to_v8(isolate, Vector3<int>{ 1, 2, 3 });
+Vector3<int> vec3 = v8pp::from_v8<Vector3<int>>(isolate, vec3_js); // == { 1, 2, 3 }
+```
diff --git a/docs/exceptions.md b/docs/exceptions.md
new file mode 100644
index 0000000..b2ebdf9
--- /dev/null
+++ b/docs/exceptions.md
@@ -0,0 +1,22 @@
+# Exceptions
+
+The library allows to throw exceptions from C++ code. Such exceptions will be
+converted to `v8::Exception::Error` and can be catched in JavaScript code.
+
+It is also possible to throw a V8 exception with
+`v8pp::throw_ex(v8::Isolate* isolate, char const* str, exception_ctor)`
+function declared in a [`v8pp/throw_ex.hpp`](../v8pp/throw_ex.hpp) header,
+where `exception_ctor` is a `v8::Exception` constructor:
+
+  * `v8::Exception::Error` (default)
+  * `v8::Exception::RangeError`
+  * `v8::Exception::ReferenceError`
+  * `v8::Exception::SyntaxError`
+  * `v8::Exception::TypeError`
+
+
+```c++
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+v8::Local<v8::Value> ex = v8pp::throw_ex(isolate, "my error message");
+```
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..1534a24
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,18 @@
+---
+layout: page
+title: v8pp documentation
+description: Uncompleted documentation on v8pp usage and internals.
+---
+
+# Table of Contents
+
+* [Data conversion](./convert.md)
+* [Exceptions](./exceptions.md)
+* [Wrapping C++ functions and classes](wrapping.md)
+* [Persistent handles](persistent.md)
+* [Utility functions](utilities.md)
+* [Context](context.md)
+* [Plugins](plugins.md)
+* [Node.js addons](addons.md)
+* [Compile-time configuration](config.md)
+* [Auto-generated Doxygen documentation](doc/html/index.html)
diff --git a/docs/persistent.md b/docs/persistent.md
new file mode 100644
index 0000000..88b3a6b
--- /dev/null
+++ b/docs/persistent.md
@@ -0,0 +1,8 @@
+# Persistent handles
+
+The library has declared a `v8pp::persistent_ptr<T>` class template in a
+[`v8pp/persistent.hpp`](../v8pp/persistent.hpp) file to store 
+[wrapped](wrapping.md) C++ objects in V8 persistent handles.
+
+This class template behavies like a smart pointer and allows to aggregate
+wrapped C++ objects inside of other wrapped C++ objects.
\ No newline at end of file
diff --git a/docs/plugins.md b/docs/plugins.md
new file mode 100644
index 0000000..e97f21d
--- /dev/null
+++ b/docs/plugins.md
@@ -0,0 +1,28 @@
+# Plugins
+
+The library allows to use a simple loadable C++ plugins for V8 engine embedded
+in a program. A target platform should support dynamically loadable modules
+(i.e. `.so` or `.dll` libraries). The target application should contain
+[`v8pp::context`](./context.md) implementation from a
+[`v8pp/context.cpp`](../v8pp/context.cpp) file.
+
+Each plugin should export an initialization procedure declared as
+`V8PP_PLUGIN_INIT(v8::Isolate* isolate)`. This init procedure adds bindings to
+the V8 `isolate` instance and should return an exported object:
+
+```c++
+// in a plugin shared library
+V8PP_PLUGIN_INIT(v8::Isolate* isolate)
+{
+       return v8pp::to_v8(isolate, 42);
+}
+```
+
+The exported value retuned is availbale as a `require()` result in JavaScript:
+
+```js
+var plugin_exports = require('plugin');
+console.log(plugin_exports); // 42
+```
+
+See [`plugins`](../plugins) directory for samples.
diff --git a/docs/utilities.md b/docs/utilities.md
new file mode 100644
index 0000000..1f7588e
--- /dev/null
+++ b/docs/utilities.md
@@ -0,0 +1,110 @@
+# Utilities
+
+`v8pp` contains some utilty functions which maybe helpful to interact with V8.
+
+## Objects
+
+Sometimes it maybe handy to get and set properties from/to a `v8::Object` as
+C++ values. Header file [`v8pp/object.hpp`](../v8pp/object.hpp) contains
+function templates for these tasks.
+
+### Get an attribute from V8 object
+
+Function `bool v8pp::get_option(v8::Isolate* isolate, v8::Handle<v8::Object> object, const* name, T& value)`
+allows to get an optional C++ `value` from a V8 `object` by `name`. Symbols
+`.` in the `name` delimit sub-object names.
+
+The functon returns `false` if there is no such named value in the `options`.
+
+```c++
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+v8::Handle<v8::Object> object; // some object, say from JavaScript code
+
+bool flag = true;
+int var;
+SomeClass some;
+
+bool const flag_exists = v8pp::get_option(isolate, object, "flag", flag);
+if (!flag_exists)
+{
+       assert(flag == true);
+}
+
+// get an option from a sub-object, set default value for it before
+v8pp::get_option(isolate, object, "some.sub.var", var = 1);
+
+// get complex object (wrapped with v8pp::class_<SomeClass> or specialized
+// with v8pp::convert<SomeClass>)
+v8pp::get_option(isolate, object, "some", some);
+```
+
+### Set an attribute in V8 object
+
+Function `bool v8pp::set_option(v8::Isolate* isolate, v8::Handle<v8::Object> object,  const* name, T const& 
value)`
+sets a C++ `value` in a V8 `object` by `name`. Symbols `.` in the `name`
+delimit sub-object names.
+
+The function returns `false` if there is no such named value in the `options`.
+
+Function `void v8pp::set_const(v8::Isolate* isolate, v8::Handle<v8::Object> object, char const* name, T 
const& value)`
+sets a constant C++ `value` in a V8 `object` by `name`. 
+
+Note this function doesn't support sub-object names.
+
+```c++
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+v8::Handle<v8::Object> object = v8::Object::New(isolate);
+
+v8pp::set_option(isolate, object, "flag", true);
+
+// set option in sub object
+int var = 42;
+if (!v8pp::set_option(isolate, object, "some.sub.var", var))
+{
+       throw std::runtime_error("object some.sub doesn't exists");
+}
+
+SomeClass some;
+// set complex object wrapped with v8pp::class_<SomeClass>
+// or specialized with v8pp::convert<SomeClass>
+v8pp::set_option(isolate, object, "some", some);
+
+v8pp::set_const(isolate, object, "PI", 3.1415926);
+```
+
+
+## JSON
+
+V8 library has a `JSON` object in JavaScript, but unfortunatly has no
+published C++ API for it.
+
+Header file [`v8pp/json.hpp`](../v8pp/json.hpp) contains a pair of functions
+for JSON manipulation.
+
+To stringify a V8 value to JSON use function
+`std::string v8pp::json_str(v8::Isolate* isolate, v8::Handle<v8::Value> value)` 
+
+To parse a JSON string to V8 value use function
+`v8::Handle<v8::Value> v8pp::json_parse(v8::Isolate* isolate, std::string const& str)`
+
+```c++
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+std::string const empty_str = v8pp::json_str(isolate, v8::Local<v8::Value>{}); // empty_str == ""
+std::string const int_str = v8pp::json_str(isolate, v8pp::to_v8(isolate, 24)); // int_str == "24"
+
+v8::Local<v8::Value> obj = v8pp::json_parse(isolate, R"({ "x":1, "y":2.2, "z":"abc" })");
+v8::Local<v8::Value> arr = v8pp::json_parse(isolate, R"([ 1, 2, 3 ])");
+```
+
+
+## Functions
+
+To call a `v8::Function` with arbitrary number of arguments use
+`v8::Handle<v8::Value> call_v8(v8::Isolate* isolate, v8::Handle<v8::Function> func, v8::Handle<v8::Value> 
recv, Args... args)`
+function from [`v8pp/call_v8.hpp`](../v8pp/call_v8.hpp) header file.
+
+This function converts supplied arguments to V8 values using `v8pp::to_v8()`
+and invokes the supplied V8 function `func` with `recv` object as `this`.
+
+The function returns result of `func->Call(recv, args...)`.
\ No newline at end of file
diff --git a/docs/wrapping.md b/docs/wrapping.md
new file mode 100644
index 0000000..0fd0e61
--- /dev/null
+++ b/docs/wrapping.md
@@ -0,0 +1,204 @@
+# Wrapping C++ code
+
+V8 library uses `v8::ObjectTemplate` to bind C++ objects into JavaScript
+and `v8::FunctionTemplate` to call C++ functions from JavaScript.
+
+## Wrapping C++ functions
+
+To create a new `v8::FunctionTemplate` for an arbitrary C++ function `func`
+use a function template `v8::Handle<v8::FunctionTemplate> v8pp::wrap_function_template(v8::Isolate* isolate, 
F func)`
+
+When a function generated from such a function template is being invoked in
+JavaScript, all function arguments will be converted from `v8::Value`s to
+corresponding C++ values. Then the C++ function `func` will be called and its
+return type would be converted back to `v8::Value`. For the C++ function
+that returns `void` a `v8::Undefined` will be returned.
+
+If the wrapped C++ function throws an exception, a `v8::Exception::Error` will
+be returned into calling JavaScript code.
+
+A function `v8::Handle<v8::Function> v8pp::wrap_function(v8::Isolate* isolate, char const* name, F func)`
+is used to wrap a C++ function to a `v8::Function` value. The V8 function will
+be created as anonymous when `nullptr` or `""` string literal is supplied for
+its `name`:
+
+```c++
+// C++ code
+int f(int x) { return x * 2; }
+
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+v8::Local<v8::Function> v8_fun = v8pp::wrap_function(isolate, "f", &f);
+isolate->GetCurrentContext()-> Global()->Set(v8pp::to_v8(isolate, "v8_fun"), v8_fun);
+```
+
+```js
+// JavaScript code
+var r = v8_fun(2); // 4
+```
+
+
+## Wrapping C++ objects
+
+### v8pp::module
+
+Class `v8pp::module` in a [`v8pp/module.hpp`](../v8pp/module.hpp) header file
+is a thin wrapper that constructs a `v8::ObjectTemplate`. This class also has
+a constructor to re-use an existing `v8::ObjectTemplate` instance.
+
+The `v8pp::module` class contains a number of `set(name, value)` function
+overloads that allows binding to V8 for other `v8pp::modules`, C++ functions,
+global variables, and classes wrapped with `v8pp::class_` template.
+
+These `set` functions return reference to the `v8pp::module` instance to allow
+call chaining:
+
+```c++
+// C++ code
+v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+int x = 1;
+float fun(float a, float b) { return a + b; }
+
+v8pp::module module(isolate), submodule(isolate);
+
+submodule
+       .set("x", x)       // bind C++ variable x
+       .set("f", &fun)    // bind C++ function
+       ;
+
+module
+       .set("sub", submodule) // bind submodule
+       .set_const("PI", 3.1415926)  // bind constant
+
+// create a  module object and bind it to the global V8 object
+isolate->GetCurrentContext()-> Global()->Set(v8pp::to_v8(isolate, "module"), module.new_instance());
+```
+
+```js
+// JavaScript after bindings above
+
+module.sub.x += 2; // x becomes 3 in C++
+var z = module.sub(module.sub.x, module.PI); // call C++ function fun(3, 3.1415926)
+```
+
+
+### v8pp::class_
+
+A class template in [`v8pp/class.hpp`](../v8pp/class.hpp) is used to register
+a wrapped C++ class in `v8pp` and to bind the class members into V8.
+
+Function `v8pp::property()` declared in a file
+[`v8pp/property.hpp`](../v8pp/property.hpp) allows to bind a read-only or
+read-write property to `v8pp::class_`:
+
+
+```c++
+struct X
+{
+       bool b;
+       X(bool b) : b(b) {}
+};
+
+struct Y : X
+{
+       X(int v, bool u) : X(u), var(v) {}
+       int var;
+       int fun() const { return var * 2;}
+       int get() const { return var; }
+       void set(int x) { var = x; } 
+};
+
+static void ext_fun(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       Y* self = v8pp::class_<Y>::unwrap_object(args.GetIsolate(), args.This());
+       if (self) args.GetReturnValue().Set(self->b);
+       else args.GetReturnValue().Set(args[0]);
+}
+
+// bind class X
+v8pp::class_<X> X_class(isolate);
+X_class
+       // specify X constructor signature
+       .ctor<bool>()
+       // bind class member variable
+       .set("b", &X::b)
+       // set const property
+       .set_const("str", "abc")
+       ;
+
+// Bind class Y
+v8pp::class_<Y> Y_class(isolate);
+Y_class
+       // specify Y constructor signature
+       .ctor<int, bool>()
+       // inherit bindings from base class
+       .inherit<X>()
+       // bind member functions
+       .set("get", &Y::get)
+       .set("set", &Y::set)
+       // bind read-only property
+       .set("prop", v8pp::property(&Y::fun));
+       // bind read-write property
+       .set("wprop", v8pp::property(&Y::get, &Y::set));
+       // bind a static function
+       .set("ext_fun", &ext_fun)
+       ;
+
+// set class into the module template
+module.set("X", X_class);
+module.set("Y", Y_class);
+```
+
+```javascript
+// Use bindings in JavaScript 
+var x = new module.X(true);
+assert(x.b == true);
+assert(x.str == "abc");
+
+var y = new module.Y(10, false);
+assert(y.b == false);
+assert(y.get() == 10);
+assert(y.prop == 20);
+y.set(11);
+assert(y.get() == 11);
+assert(y.wprop == 11);
+y.wprop == 12;
+assert(y.get() == 12);
+assert(y.ext_fun() == y.b);
+assert(module.Y.ext_fun(100) == 100);
+```
+
+
+### v8pp::factory
+
+Creation of  wrapped classes instances can be customized by `v8pp::factory<T>`
+class template specialization. This approach allows to wrap classes with 
+different construction policies:
+
+```c++
+class Z
+{
+public:
+       static Z* make(int) { return new Z }
+       static void done(Z* z) { delete z; }
+private:
+       Z() {}
+       ~Z() {}
+};
+
+// Specialize Z factory
+template<>
+struct v8pp::factory<Z>
+{
+       static Z* create(v8::Isolate*, int arg)
+       {
+               return Z::make(arg);
+       }
+
+       static void destroy(v8::Isolate*, Z* obj)
+       {
+               Z::done(obj);
+       }
+};
+```
diff --git a/examples/01 hello world/binding.gyp b/examples/01 hello world/binding.gyp
new file mode 100644
index 0000000..e27cda3
--- /dev/null
+++ b/examples/01 hello world/binding.gyp       
@@ -0,0 +1,11 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'sources': ['hello.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/01 hello world/hello.cc b/examples/01 hello world/hello.cc
new file mode 100644
index 0000000..5b6cf2b
--- /dev/null
+++ b/examples/01 hello world/hello.cc  
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include <v8pp/module.hpp>
+
+using namespace v8;
+
+char const* Method() {
+  return "world";
+}
+
+void init(Handle<Object> exports) {
+  v8pp::module addon(Isolate::GetCurrent());
+  addon.set("hello", &Method);
+  exports->SetPrototype(addon.new_instance());
+}
+
+NODE_MODULE(addon, init)
\ No newline at end of file
diff --git a/examples/01 hello world/hello.js b/examples/01 hello world/hello.js
new file mode 100644
index 0000000..c2a4ca3
--- /dev/null
+++ b/examples/01 hello world/hello.js  
@@ -0,0 +1,11 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+console.log(addon.hello()); // 'world'
\ No newline at end of file
diff --git a/examples/02 arguments/addon.cc b/examples/02 arguments/addon.cc
new file mode 100644
index 0000000..70a8ef1
--- /dev/null
+++ b/examples/02 arguments/addon.cc    
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include <v8pp/module.hpp>
+
+using namespace v8;
+
+double Add(double arg1, double arg2) {
+  return arg1 + arg2;
+}
+
+void Init(Handle<Object> exports) {
+  v8pp::module addon(Isolate::GetCurrent());
+  addon.set("add", &Add);
+  exports->SetPrototype(addon.new_instance());
+}
+
+NODE_MODULE(addon, Init)
\ No newline at end of file
diff --git a/examples/02 arguments/binding.gyp b/examples/02 arguments/binding.gyp
new file mode 100644
index 0000000..aee885c
--- /dev/null
+++ b/examples/02 arguments/binding.gyp 
@@ -0,0 +1,11 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'sources': ['addon.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/02 arguments/test.js b/examples/02 arguments/test.js
new file mode 100644
index 0000000..0eed279
--- /dev/null
+++ b/examples/02 arguments/test.js     
@@ -0,0 +1,11 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+console.log( 'This should be eight:', addon.add(3,5) );
diff --git a/examples/03 callbacks/addon.cc b/examples/03 callbacks/addon.cc
new file mode 100644
index 0000000..b8d1c65
--- /dev/null
+++ b/examples/03 callbacks/addon.cc    
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+
+#include <v8pp/call_v8.hpp>
+#include <v8pp/function.hpp>
+#include <v8pp/object.hpp>
+
+using namespace v8;
+
+void RunCallback(Local<Function> cb) {
+  Isolate* isolate = Isolate::GetCurrent();
+
+  v8pp::call_v8(isolate, cb, isolate->GetCurrentContext()->Global(), "hello world");
+}
+
+void Init(Handle<Object> exports, Handle<Object> module) {
+  Isolate* isolate = Isolate::GetCurrent();
+  v8pp::set_option(isolate, module, "exports", v8pp::wrap_function(isolate, "exports", &RunCallback));
+}
+
+NODE_MODULE(addon, Init)
\ No newline at end of file
diff --git a/examples/03 callbacks/binding.gyp b/examples/03 callbacks/binding.gyp
new file mode 100644
index 0000000..aee885c
--- /dev/null
+++ b/examples/03 callbacks/binding.gyp 
@@ -0,0 +1,11 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'sources': ['addon.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/03 callbacks/test.js b/examples/03 callbacks/test.js
new file mode 100644
index 0000000..821ff17
--- /dev/null
+++ b/examples/03 callbacks/test.js     
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+addon(function(msg){
+  console.log(msg); // 'hello world'
+});
\ No newline at end of file
diff --git a/examples/04 object factory/addon.cc b/examples/04 object factory/addon.cc
new file mode 100644
index 0000000..1d2af5d
--- /dev/null
+++ b/examples/04 object factory/addon.cc       
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include <v8pp/object.hpp>
+#include <v8pp/function.hpp>
+
+#include <node.h>
+
+using namespace v8;
+
+Handle<Object> CreateObject(v8::Isolate* isolate, std::string const& msg) {
+  EscapableHandleScope scope(isolate);
+
+  Local<Object> obj = Object::New(isolate);
+  v8pp::set_option(isolate, obj, "msg", msg);
+  return scope.Escape(obj);
+}
+
+void Init(Handle<Object> exports, Handle<Object> module) {
+  Isolate* isolate = Isolate::GetCurrent();
+  v8pp::set_option(isolate, module, "exports", v8pp::wrap_function(isolate, "exports", &CreateObject));
+}
+
+NODE_MODULE(addon, Init)
\ No newline at end of file
diff --git a/examples/04 object factory/binding.gyp b/examples/04 object factory/binding.gyp
new file mode 100644
index 0000000..aee885c
--- /dev/null
+++ b/examples/04 object factory/binding.gyp    
@@ -0,0 +1,11 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'sources': ['addon.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/04 object factory/test.js b/examples/04 object factory/test.js
new file mode 100644
index 0000000..75cb65c
--- /dev/null
+++ b/examples/04 object factory/test.js        
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+var obj1 = addon('hello');
+var obj2 = addon('world');
+console.log(obj1.msg+' '+obj2.msg); // 'hello world'
\ No newline at end of file
diff --git a/examples/05 function factory/addon.cc b/examples/05 function factory/addon.cc
new file mode 100644
index 0000000..e4a0b6c
--- /dev/null
+++ b/examples/05 function factory/addon.cc     
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include <v8pp/function.hpp>
+#include <v8pp/object.hpp>
+
+using namespace v8;
+
+std::string MyFunction() {
+  return "hello world";
+}
+
+Handle<Function> CreateFunction(Isolate* isolate) {
+  EscapableHandleScope scope(isolate);
+
+  Local<FunctionTemplate> tpl = v8pp::wrap_function_template(isolate, &MyFunction);
+  Local<Function> fn = tpl->GetFunction();
+
+  // omit this to make it anonymous
+  fn->SetName(v8pp::to_v8(isolate, "theFunction"));
+  return scope.Escape(fn);
+}
+
+void Init(Handle<Object> exports, Handle<Object> module) {
+  Isolate* isolate = Isolate::GetCurrent();
+  v8pp::set_option(isolate, module, "exports", v8pp::wrap_function(isolate, "exports", &CreateFunction));
+}
+
+NODE_MODULE(addon, Init)
\ No newline at end of file
diff --git a/examples/05 function factory/binding.gyp b/examples/05 function factory/binding.gyp
new file mode 100644
index 0000000..aee885c
--- /dev/null
+++ b/examples/05 function factory/binding.gyp  
@@ -0,0 +1,11 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'sources': ['addon.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/05 function factory/test.js b/examples/05 function factory/test.js
new file mode 100644
index 0000000..be7844d
--- /dev/null
+++ b/examples/05 function factory/test.js      
@@ -0,0 +1,12 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+var fn = addon();
+console.log(fn()); // 'hello world'
\ No newline at end of file
diff --git a/examples/06 wrapped objects/addon.cc b/examples/06 wrapped objects/addon.cc
new file mode 100644
index 0000000..54c13ba
--- /dev/null
+++ b/examples/06 wrapped objects/addon.cc      
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include "myobject.h"
+
+using namespace v8;
+
+void InitAll(Handle<Object> exports) {
+  MyObject::Init(exports);
+}
+
+NODE_MODULE(addon, InitAll)
\ No newline at end of file
diff --git a/examples/06 wrapped objects/binding.gyp b/examples/06 wrapped objects/binding.gyp
new file mode 100644
index 0000000..563d3b1
--- /dev/null
+++ b/examples/06 wrapped objects/binding.gyp   
@@ -0,0 +1,11 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'sources': ['addon.cc', 'myobject.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/06 wrapped objects/myobject.cc b/examples/06 wrapped objects/myobject.cc
new file mode 100644
index 0000000..24bcb33
--- /dev/null
+++ b/examples/06 wrapped objects/myobject.cc   
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "myobject.h"
+#include <node.h>
+#include <v8pp/class.hpp>
+#include <v8pp/module.hpp>
+
+using namespace v8;
+
+void MyObject::Init(Handle<Object> exports) {
+  Isolate* isolate = Isolate::GetCurrent();
+
+  // Prepare class binding
+  v8pp::class_<MyObject> MyObject_class(isolate);
+
+  // constructor signature
+  MyObject_class.ctor<const FunctionCallbackInfo<Value>&>();
+
+  // Prototype
+  MyObject_class.set("plusOne", &MyObject::PlusOne);
+
+  v8pp::module addon(isolate);
+  addon.set("MyObject", MyObject_class);
+
+  exports->SetPrototype(addon.new_instance());
+  node::AtExit([](void* param)
+  {
+      v8pp::cleanup(static_cast<Isolate*>(param));
+  }, isolate);
+}
+
+MyObject::MyObject(const FunctionCallbackInfo<Value>& args) {
+  value_ = v8pp::from_v8<double>(args.GetIsolate(), args[0], 0);
+}
+
+double MyObject::PlusOne() {
+  value_ += 1;
+  return value_;
+}
diff --git a/examples/06 wrapped objects/myobject.h b/examples/06 wrapped objects/myobject.h
new file mode 100644
index 0000000..bd68f94
--- /dev/null
+++ b/examples/06 wrapped objects/myobject.h    
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <v8.h>
+
+class MyObject {
+ public:
+  static void Init(v8::Handle<v8::Object> exports);
+
+  explicit MyObject(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+ private:
+  double PlusOne();
+  double value_;
+};
+
+#endif
diff --git a/examples/06 wrapped objects/test.js b/examples/06 wrapped objects/test.js
new file mode 100644
index 0000000..7e0df37
--- /dev/null
+++ b/examples/06 wrapped objects/test.js       
@@ -0,0 +1,14 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+var obj = new addon.MyObject(10);
+console.log( obj.plusOne() ); // 11
+console.log( obj.plusOne() ); // 12
+console.log( obj.plusOne() ); // 13
diff --git a/examples/07 wrapped objects factory/addon.cc b/examples/07 wrapped objects factory/addon.cc
new file mode 100644
index 0000000..c155aff
--- /dev/null
+++ b/examples/07 wrapped objects factory/addon.cc      
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include <v8pp/class.hpp>
+#include <v8pp/function.hpp>
+#include <v8pp/object.hpp>
+
+#include "myobject.h"
+
+using namespace v8;
+
+static Handle<Object> CreateObject(const FunctionCallbackInfo<Value>& args) {
+  MyObject* obj = new MyObject(args);
+  return v8pp::class_<MyObject>::import_external(args.GetIsolate(), obj);
+}
+
+void InitAll(Handle<Object> exports, Handle<Object> module) {
+  MyObject::Init();
+
+  Isolate* isolate = Isolate::GetCurrent();
+  v8pp::set_option(isolate, module, "exports", v8pp::wrap_function(isolate, "exports", &CreateObject));
+  node::AtExit([](void* param)
+  {
+      v8pp::cleanup(static_cast<Isolate*>(param));
+  }, isolate);
+}
+
+NODE_MODULE(addon, InitAll)
diff --git a/examples/07 wrapped objects factory/binding.gyp b/examples/07 wrapped objects factory/binding.gyp
new file mode 100644
index 0000000..0f020f1
--- /dev/null
+++ b/examples/07 wrapped objects factory/binding.gyp   
@@ -0,0 +1,12 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'msvs_settings': { 'VCLinkerTool': { 'AdditionalOptions': ['/FORCE:MULTIPLE'] } },
+                       'sources': ['addon.cc', 'myobject.cc'],
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/07 wrapped objects factory/myobject.cc b/examples/07 wrapped objects factory/myobject.cc
new file mode 100644
index 0000000..0420c36
--- /dev/null
+++ b/examples/07 wrapped objects factory/myobject.cc   
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "myobject.h"
+#include <v8pp/class.hpp>
+#include <v8pp/module.hpp>
+
+using namespace v8;
+
+void MyObject::Init() {
+  Isolate* isolate = Isolate::GetCurrent();
+
+  // Prepare class binding
+  v8pp::class_<MyObject> MyObject_class(isolate);
+
+  // Prototype
+  MyObject_class.set("plusOne", &MyObject::PlusOne);
+
+  v8pp::module bindings(isolate);
+  bindings.set("MyObject", MyObject_class);
+
+  static Persistent<Object> bindings_(isolate, bindings.new_instance());
+}
+
+MyObject::MyObject(const FunctionCallbackInfo<Value>& args) {
+  value_ = v8pp::from_v8<double>(args.GetIsolate(), args[0], 0);
+}
+
+double MyObject::PlusOne() {
+  value_ += 1;
+  return value_;
+}
diff --git a/examples/07 wrapped objects factory/myobject.h b/examples/07 wrapped objects factory/myobject.h
new file mode 100644
index 0000000..f46b4e3
--- /dev/null
+++ b/examples/07 wrapped objects factory/myobject.h    
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <v8.h>
+
+class MyObject {
+ public:
+  static void Init();
+
+  explicit MyObject(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+ private:
+  double PlusOne();
+  double value_;
+};
+
+#endif
diff --git a/examples/07 wrapped objects factory/test.js b/examples/07 wrapped objects factory/test.js
new file mode 100644
index 0000000..eb04910
--- /dev/null
+++ b/examples/07 wrapped objects factory/test.js       
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var createObject = require('./build/Release/addon');
+
+var obj = createObject(10);
+console.log( obj.plusOne() ); // 11
+console.log( obj.plusOne() ); // 12
+console.log( obj.plusOne() ); // 13
+
+var obj2 = createObject(20);
+console.log( obj2.plusOne() ); // 21
+console.log( obj2.plusOne() ); // 22
+console.log( obj2.plusOne() ); // 23
diff --git a/examples/08 passing wrapped objects/addon.cc b/examples/08 passing wrapped objects/addon.cc
new file mode 100644
index 0000000..046ea6d
--- /dev/null
+++ b/examples/08 passing wrapped objects/addon.cc      
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <node.h>
+#include <v8pp/module.hpp>
+#include <v8pp/class.hpp>
+#include <v8pp/function.hpp>
+#include <v8pp/object.hpp>
+
+#include "myobject.h"
+
+using namespace v8;
+
+Handle<Object> CreateObject(const FunctionCallbackInfo<Value>& args) {
+  MyObject* obj = new MyObject(args);
+  return v8pp::class_<MyObject>::import_external(args.GetIsolate(), obj);
+}
+
+double Add(MyObject const& obj1, MyObject const& obj2) {
+  return obj1.value() + obj2.value();
+}
+
+void InitAll(Handle<Object> exports) {
+  Isolate* isolate = Isolate::GetCurrent();
+
+  v8pp::class_<MyObject> MyObject_class(isolate);
+
+  v8pp::module addon(isolate);
+  addon.set("MyObject", MyObject_class); 
+  addon.set("createObject", &CreateObject);
+  addon.set("add", &Add);
+  exports->SetPrototype(addon.new_instance());
+  node::AtExit([](void* param)
+  {
+      v8pp::cleanup(static_cast<Isolate*>(param));
+  }, isolate);
+}
+
+NODE_MODULE(addon, InitAll)
diff --git a/examples/08 passing wrapped objects/binding.gyp b/examples/08 passing wrapped objects/binding.gyp
new file mode 100644
index 0000000..d5a4470
--- /dev/null
+++ b/examples/08 passing wrapped objects/binding.gyp   
@@ -0,0 +1,13 @@
+{
+       'targets':
+       [
+               {
+                       'target_name': 'addon',
+                       'include_dirs': ['../..'],
+                       'cflags_cc': ['-std=c++11', '-fexceptions'],
+                       'msvs_settings': { 'VCLinkerTool': { 'AdditionalOptions': ['/FORCE:MULTIPLE'] } },
+                       'sources': ['addon.cc', 'myobject.cc'],
+                       'msvs_settings': { 'VCLinkerTool': { 'AdditionalOptions': ['/FORCE:MULTIPLE'] } },
+               }
+       ]
+}
\ No newline at end of file
diff --git a/examples/08 passing wrapped objects/myobject.cc b/examples/08 passing wrapped objects/myobject.cc
new file mode 100644
index 0000000..3bb86b9
--- /dev/null
+++ b/examples/08 passing wrapped objects/myobject.cc   
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "myobject.h"
+#include <v8pp/convert.hpp>
+
+using namespace v8;
+
+MyObject::MyObject(const FunctionCallbackInfo<Value>& args) {
+  value_ = v8pp::from_v8<double>(args.GetIsolate(), args[0], 0);
+}
diff --git a/examples/08 passing wrapped objects/myobject.h b/examples/08 passing wrapped objects/myobject.h
new file mode 100644
index 0000000..80cbad5
--- /dev/null
+++ b/examples/08 passing wrapped objects/myobject.h    
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <v8.h>
+
+class MyObject {
+ public:
+  explicit MyObject(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+  inline double value() const { return value_; }
+
+ private:
+  double value_;
+};
+
+#endif
diff --git a/examples/08 passing wrapped objects/test.js b/examples/08 passing wrapped objects/test.js
new file mode 100644
index 0000000..3898f4d
--- /dev/null
+++ b/examples/08 passing wrapped objects/test.js       
@@ -0,0 +1,15 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var addon = require('./build/Release/addon');
+
+var obj1 = addon.createObject(10);
+var obj2 = addon.createObject(20);
+var result = addon.add(obj1, obj2);
+
+console.log(result); // 30
diff --git a/fetch-v8.py b/fetch-v8.py
new file mode 100644
index 0000000..05c192a
--- /dev/null
+++ b/fetch-v8.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+import os
+import subprocess
+import shutil
+
+V8_URL = 'https://chromium.googlesource.com/v8/v8.git'
+
+def fetch(url, target):
+       parts = url.split('.git@')
+       if len(parts) > 1:
+               url = parts[0] + '.git'
+               ref = parts[1]
+       else:
+               ref = 'HEAD'
+       print 'Fetch %s@%s to %s' % (url, ref, target)
+
+       if not os.path.isdir(os.path.join(target, '.git')):
+               subprocess.call(['git', 'init', target])
+       subprocess.call(['git', 'fetch', '--depth=1', url, ref], cwd=target)
+       subprocess.call(['git', 'checkout', '-B', 'Branch_' + ref, 'FETCH_HEAD'], cwd=target)
+       
+
+fetch(V8_URL, 'v8')
+
+deps = open('v8/DEPS').read()
+
+Var = lambda name: vars[name]
+exec deps
+
+for dep in ['v8/base/trace_event/common', 'v8/build', 'v8/testing/gtest', 'v8/tools/gyp', 'v8/tools/clang', 
'v8/third_party/icu']:
+       fetch(deps[dep], dep)
\ No newline at end of file
diff --git a/include_dirs.js b/include_dirs.js
new file mode 100644
index 0000000..2847784
--- /dev/null
+++ b/include_dirs.js
@@ -0,0 +1 @@
+console.log(require('path').relative('.', __dirname));
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..572846c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,15 @@
+{
+  "name": "v8pp",
+  "version": "1.4.0",
+  "description": "C++ bindings for V8",
+  "keywords": [ "V8", "native", "addon", "module", "bindings" ],
+  "main": "include_dirs.js",
+  "repository": { "type": "git", "url": "git://github.com/pmed/v8pp.git" },
+  "author": "Pavel Medvedev <pmedvedev gmail com>",
+  "license": "BSL-1.0",
+  "bugs": { "url": "https://github.com/pmed/v8pp/issues";  },
+  "homepage": "https://github.com/pmed/v8pp#readme";,
+  "files": ["docs", "examples", "v8pp/*.hpp", "include_dirs.js",
+    "COPYING", "LICENSE_1_0.txt", "README.md"
+  ]
+}
diff --git a/plugins/console.cpp b/plugins/console.cpp
new file mode 100644
index 0000000..be4ae19
--- /dev/null
+++ b/plugins/console.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <v8pp/module.hpp>
+#include <v8pp/config.hpp>
+
+namespace console {
+
+void log(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       v8::HandleScope handle_scope(args.GetIsolate());
+
+       for (int i = 0; i < args.Length(); ++i)
+       {
+               if (i > 0) std::cout << ' ';
+               v8::String::Utf8Value str(args[i]);
+               std::cout <<  *str;
+       }
+       std::cout << std::endl;
+}
+
+v8::Handle<v8::Value> init(v8::Isolate* isolate)
+{
+       v8pp::module m(isolate);
+       m.set("log", &log);
+       return m.new_instance();
+}
+
+} // namespace console
+
+V8PP_PLUGIN_INIT(v8::Isolate* isolate)
+{
+       return console::init(isolate);
+}
diff --git a/plugins/console.vcxproj b/plugins/console.vcxproj
new file mode 100644
index 0000000..db4181c
--- /dev/null
+++ b/plugins/console.vcxproj
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props" 
Condition="Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props" 
Condition="Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" />
+  <Import Project="..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props" 
Condition="Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" />
+  <Import Project="..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props" 
Condition="Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props" 
Condition="Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" />
+  <Import Project="..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props" 
Condition="Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{967D7CE6-8AD1-465C-A838-0A7E666DC1AE}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>console</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CONSOLE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CONSOLE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CONSOLE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CONSOLE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="console.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\v8pp\v8pp.vcxproj">
+      <Project>{2e6cfc3d-5a08-4909-8d1a-3469063d169b}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet 
Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. 
The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props'))" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/plugins/console.vcxproj.filters b/plugins/console.vcxproj.filters
new file mode 100644
index 0000000..f01be04
--- /dev/null
+++ b/plugins/console.vcxproj.filters
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <ItemGroup>
+    <ClCompile Include="console.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/plugins/file.cpp b/plugins/file.cpp
new file mode 100644
index 0000000..7033a35
--- /dev/null
+++ b/plugins/file.cpp
@@ -0,0 +1,147 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <v8pp/module.hpp>
+#include <v8pp/class.hpp>
+#include <v8pp/config.hpp>
+
+#include <fstream>
+
+namespace file {
+
+class file_base
+{
+public:
+       bool is_open() const { return stream_.is_open(); }
+       bool good() const { return stream_.good(); }
+       bool eof() const { return stream_.eof(); }
+       void close() { stream_.close(); }
+
+protected:
+       std::fstream stream_;
+};
+
+class file_writer : public file_base
+{
+public:
+       explicit file_writer(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               if (args.Length() == 1)
+               {
+                       v8::String::Utf8Value str(args[0]);
+                       open(*str);
+               }
+       }
+
+       bool open(char const* path)
+       {
+               stream_.open(path, std::ios_base::out);
+               return stream_.good();
+       }
+
+       void print(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               v8::HandleScope scope(args.GetIsolate());
+
+               for (int i = 0; i < args.Length(); ++i)
+               {
+                       if (i > 0) stream_ << ' ';
+                       v8::String::Utf8Value str(args[i]);
+                       stream_ << *str;
+               }
+       }
+
+       void println(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               print(args);
+               stream_ << std::endl;
+       }
+};
+
+class file_reader : public file_base
+{
+public:
+       explicit file_reader(char const* path)
+       {
+               open(path);
+       }
+
+       bool open(const char* path)
+       {
+               stream_.open(path, std::ios_base::in);
+               return stream_.good();
+       }
+
+       v8::Handle<v8::Value> getline(v8::Isolate* isolate)
+       {
+               if ( stream_.good() && ! stream_.eof())
+               {
+                       std::string line;
+                       std::getline(stream_, line);
+                       return v8pp::to_v8(isolate, line);
+               }
+               else
+               {
+                       return v8::Undefined(isolate);
+               }
+       }
+};
+
+v8::Handle<v8::Value> init(v8::Isolate* isolate)
+{
+       v8::EscapableHandleScope scope(isolate);
+
+       // file_base binding, no .ctor() specified, object creation disallowed in JavaScript
+       v8pp::class_<file_base> file_base_class(isolate);
+       file_base_class
+               .set("close", &file_base::close)
+               .set("good", &file_base::good)
+               .set("is_open", &file_base::is_open)
+               .set("eof", &file_base::eof)
+               ;
+
+       // .ctor<> template arguments declares types of file_writer constructor
+       // file_writer inherits from file_base_class
+       v8pp::class_<file_writer> file_writer_class(isolate);
+       file_writer_class
+               .ctor<v8::FunctionCallbackInfo<v8::Value> const&>()
+               .inherit<file_base>()
+               .set("open", &file_writer::open)
+               .set("print", &file_writer::print)
+               .set("println", &file_writer::println)
+               ;
+
+       // .ctor<> template arguments declares types of file_reader constructor.
+       // file_base inherits from file_base_class
+       v8pp::class_<file_reader> file_reader_class(isolate);
+       file_reader_class
+               .ctor<char const*>()
+               .inherit<file_base>()
+               .set("open", &file_reader::open)
+               .set("getln", &file_reader::getline)
+               ;
+
+       // Create a module to add classes and functions to and return a
+       // new instance of the module to be embedded into the v8 context
+       v8pp::module m(isolate);
+       m.set("rename", [](char const* src, char const* dest) -> bool
+       {
+               return std::rename(src, dest) == 0;
+       });
+       m.set("writer", file_writer_class);
+       m.set("reader", file_reader_class);
+
+       return scope.Escape(m.new_instance());
+}
+
+} // namespace file
+
+V8PP_PLUGIN_INIT(v8::Isolate* isolate)
+{
+       return file::init(isolate);
+}
diff --git a/plugins/file.vcxproj b/plugins/file.vcxproj
new file mode 100644
index 0000000..73ede83
--- /dev/null
+++ b/plugins/file.vcxproj
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props" 
Condition="Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props" 
Condition="Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" />
+  <Import Project="..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props" 
Condition="Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" />
+  <Import Project="..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props" 
Condition="Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props" 
Condition="Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" />
+  <Import Project="..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props" 
Condition="Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{300469B1-31DA-4485-A75B-111C78697B16}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>file</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="file.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\v8pp\v8pp.vcxproj">
+      <Project>{2e6cfc3d-5a08-4909-8d1a-3469063d169b}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet 
Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. 
The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props'))" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/plugins/file.vcxproj.filters b/plugins/file.vcxproj.filters
new file mode 100644
index 0000000..4cc0422
--- /dev/null
+++ b/plugins/file.vcxproj.filters
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <ItemGroup>
+    <ClCompile Include="file.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/plugins/packages.config b/plugins/packages.config
new file mode 100644
index 0000000..a9b883f
--- /dev/null
+++ b/plugins/packages.config
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="v8.redist-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.redist-v120-x86" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.symbols-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.symbols-v120-x86" version="5.4.500.8" targetFramework="native" />
+  <package id="v8-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8-v120-x86" version="5.4.500.8" targetFramework="native" />
+</packages>
\ No newline at end of file
diff --git a/test/console.js b/test/console.js
new file mode 100644
index 0000000..f68a286
--- /dev/null
+++ b/test/console.js
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var console = require('console')
+
+console.log('yo', 'baby', 4.2, null)
+
+var c2 = require('console')
+c2.log('conker 2')
+
+function pando() {
+    this.friend = 1
+    this.masto = require('console')
+    this.whack = function() {
+        this.masto.log('truckman')
+    }
+}
+
+var c = new pando()
+c.whack()
+
diff --git a/test/file.js b/test/file.js
new file mode 100644
index 0000000..1648825
--- /dev/null
+++ b/test/file.js
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+var file    = require('file'),
+    console = require('console')
+
+var write1 = new file.writer()
+var write2 = new file.writer("bunko")
+
+console.log("write1 is writer", file.writer, write1, (write1 instanceof file.writer))
+
+if (! write1.open("punko") || ! write2.is_open()) {
+    console.log("could not load file for write")
+}
+else {
+    write1.println("hello friend")
+    write2.println("hollo frond")
+    write1.println("fond of the night")
+    write2.println("frond frond of the night")
+    write1.close()
+    write2.close()
+}
+
+if (! file.rename("punko", "newpunko"))
+    console.log("could not rename file")
+
+var read1 = new file.reader("newpunko")
+if (! read1.is_open()) {
+    console.log("could not load punko for read")
+}
+else for (var line = read1.getln(); line; line = read1.getln()) {
+    console.log("tata",line)
+}
+
+var read2 = new file.reader("bunko")
+if (! read2.is_open()) {
+    console.log("could not load bunko for read")
+}
+else for (var line = read2.getln(); line; line = read2.getln()) {
+    console.log("papa",line)
+}
+
+console.log("exit")
diff --git a/test/main.cpp b/test/main.cpp
new file mode 100644
index 0000000..9f639cc
--- /dev/null
+++ b/test/main.cpp
@@ -0,0 +1,146 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <algorithm>
+#include <memory>
+#include <vector>
+#include <exception>
+#include <string>
+
+#include "v8.h"
+#include "libplatform/libplatform.h"
+
+#include "v8pp/context.hpp"
+
+void run_tests()
+{
+       void test_utility();
+       void test_context();
+       void test_convert();
+       void test_throw_ex();
+       void test_call_v8();
+       void test_call_from_v8();
+       void test_function();
+       void test_factory();
+       void test_module();
+       void test_class();
+       void test_property();
+       void test_object();
+       void test_json();
+
+       std::pair<char const*, void(*)()> tests[] =
+       {
+               { "test_utility", test_utility },
+               { "test_context", test_context },
+               { "test_convert", test_convert },
+               { "test_throw_ex", test_throw_ex },
+               { "test_function", test_function },
+               { "test_call_v8", test_call_v8 },
+               { "test_call_from_v8", test_call_from_v8 },
+               { "test_factory", test_factory },
+               { "test_module", test_module },
+               { "test_class", test_class },
+               { "test_property", test_property },
+               { "test_object", test_object },
+               { "test_json", test_json },
+       };
+
+       for (auto const& test : tests)
+       {
+               std::cout << test.first;
+               try
+               {
+                       test.second();
+                       std::cout << " ok";
+               }
+               catch (std::exception const& ex)
+               {
+                       std::cerr << " error: " << ex.what();
+                       exit(EXIT_FAILURE);
+               }
+               std::cout << std::endl;
+       }
+}
+
+int main(int argc, char const * argv[])
+{
+       std::vector<std::string> scripts;
+       std::string lib_path;
+       bool do_tests = false;
+
+       for (int i = 1; i < argc; ++i)
+       {
+               std::string const arg = argv[i];
+               if (arg == "-h" || arg == "--help")
+               {
+                       std::cout << "Usage: " << argv[0] << " [arguments] [script]\n"
+                               << "Arguments:\n"
+                               << "  --help,-h           Print this message and exit\n"
+                               << "  --version,-v        Print V8 version\n"
+                               << "  --lib-path <dir>    Set <dir> for plugins library path\n"
+                               << "  --run-tests         Run library tests\n"
+                               ;
+                       return EXIT_SUCCESS;
+               }
+               else if (arg == "-v" || arg == "--version")
+               {
+                       std::cout << "V8 version " << v8::V8::GetVersion() << std::endl;
+               }
+               else if (arg == "--lib-path")
+               {
+                       ++i;
+                       if (i < argc) lib_path = argv[i];
+               }
+               else if (arg == "--run-tests")
+               {
+                       do_tests = true;
+               }
+               else
+               {
+                       scripts.push_back(arg);
+               }
+       }
+
+       v8::V8::InitializeICU();
+       //v8::V8::InitializeExternalStartupData(argv[0]);
+       std::unique_ptr<v8::Platform> platform(v8::platform::CreateDefaultPlatform());
+       v8::V8::InitializePlatform(platform.get());
+       v8::V8::Initialize();
+
+       if (do_tests || scripts.empty())
+       {
+               run_tests();
+       }
+
+       int result = EXIT_SUCCESS;
+       try
+       {
+               v8pp::context context;
+
+               if (!lib_path.empty())
+               {
+                       context.set_lib_path(lib_path);
+               }
+               for (std::string const& script : scripts)
+               {
+                       v8::HandleScope scope(context.isolate());
+                       context.run_file(script);
+               }
+       }
+       catch (std::exception & ex)
+       {
+               std::cerr << ex.what() << std::endl;
+               result = EXIT_FAILURE;
+       }
+
+       v8::V8::Dispose();
+       v8::V8::ShutdownPlatform();
+
+       return result;
+}
diff --git a/test/packages.config b/test/packages.config
new file mode 100644
index 0000000..a9b883f
--- /dev/null
+++ b/test/packages.config
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="v8.redist-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.redist-v120-x86" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.symbols-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.symbols-v120-x86" version="5.4.500.8" targetFramework="native" />
+  <package id="v8-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8-v120-x86" version="5.4.500.8" targetFramework="native" />
+</packages>
\ No newline at end of file
diff --git a/test/test.hpp b/test/test.hpp
new file mode 100644
index 0000000..0fe478f
--- /dev/null
+++ b/test/test.hpp
@@ -0,0 +1,126 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iosfwd>
+#include <array>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include "v8pp/context.hpp"
+#include "v8pp/convert.hpp"
+
+template<typename Char, typename Traits,
+       typename T, typename Alloc, typename ...Other,
+       template<typename, typename, typename ...> class Sequence>
+std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
+       Sequence<T, Alloc, Other...> const& sequence)
+{
+       os << '[';
+       bool first = true;
+       for (auto const& item : sequence)
+       {
+               if (!first) os << ", ";
+               os << item;
+               first = false;
+       }
+       os << ']';
+       return os;
+}
+
+template<typename Char, typename Traits, typename T, size_t N>
+std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
+       std::array<T, N> const& array)
+{
+       os << '[';
+       bool first = true;
+       for (auto const& item : array)
+       {
+               if (!first) os << ", ";
+               os << item;
+               first = false;
+       }
+       os << ']';
+       return os;
+}
+
+template<typename Char, typename Traits,
+       typename Key, typename Value, typename Less, typename Alloc, typename ...Other,
+       template<typename, typename, typename, typename, typename ...> class Mapping>
+std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
+       Mapping<Key, Value, Less, Alloc, Other...> const& mapping)
+{
+       os << '{';
+       bool first = true;
+       for (auto const& item : mapping)
+       {
+               if (!first) os << ", ";
+               os << item.first << ": " <<item.second;
+               first = false;
+       }
+       os << '}';
+       return os;
+}
+
+template<typename Char, typename Traits,
+       typename Enum, typename = typename std::enable_if<std::is_enum<Enum>::value>::type>
+std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, Enum value)
+{
+       return os << static_cast<typename std::underlying_type<Enum>::type>(value);
+}
+
+inline void check(std::string msg, bool condition)
+{
+       if (!condition)
+       {
+               std::stringstream ss;
+               ss << "check failed: " << msg;
+               throw std::runtime_error(ss.str());
+       }
+}
+
+template<typename T, typename U>
+void check_eq(std::string msg, T actual, U expected)
+{
+       if (actual != expected)
+       {
+               std::stringstream ss;
+               ss << msg << " expected: '" << expected << "' actual: '" << actual << "'";
+               check(ss.str(), false);
+       }
+}
+
+template<typename Ex, typename F>
+void check_ex(std::string msg, F&& f)
+{
+       try
+       {
+               f();
+               check(msg + " expected " + typeid(Ex).name() + " exception", false);
+       }
+       catch (Ex const&)
+       {
+       }
+}
+
+template<typename T>
+T run_script(v8pp::context& context, std::string const& source)
+{
+       v8::Isolate* isolate = context.isolate();
+
+       v8::HandleScope scope(isolate);
+       v8::TryCatch try_catch;
+       v8::Handle<v8::Value> result = context.run_script(source);
+       if (try_catch.HasCaught())
+       {
+               std::string const msg = v8pp::from_v8<std::string>(isolate,
+                       try_catch.Exception()->ToString());
+               throw std::runtime_error(msg);
+       }
+       return v8pp::from_v8<T>(isolate, result);
+}
diff --git a/test/test.vcxproj b/test/test.vcxproj
new file mode 100644
index 0000000..9dfc3c8
--- /dev/null
+++ b/test/test.vcxproj
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props" 
Condition="Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props" 
Condition="Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" />
+  <Import Project="..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props" 
Condition="Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" />
+  <Import Project="..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props" 
Condition="Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props" 
Condition="Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" />
+  <Import Project="..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props" 
Condition="Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="test_call_from_v8.cpp" />
+    <ClCompile Include="test_call_v8.cpp" />
+    <ClCompile Include="test_class.cpp" />
+    <ClCompile Include="test_context.cpp" />
+    <ClCompile Include="test_convert.cpp" />
+    <ClCompile Include="test_factory.cpp" />
+    <ClCompile Include="test_function.cpp" />
+    <ClCompile Include="test_json.cpp" />
+    <ClCompile Include="test_module.cpp" />
+    <ClCompile Include="test_object.cpp" />
+    <ClCompile Include="test_property.cpp" />
+    <ClCompile Include="test_throw_ex.cpp" />
+    <ClCompile Include="test_utility.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\v8pp\v8pp.vcxproj">
+      <Project>{2e6cfc3d-5a08-4909-8d1a-3469063d169b}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="test.hpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{69779536-9D04-48B2-B853-4E1B761A7A50}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>test</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;V8_IMMINENT_DEPRECATION_WARNINGSzzz;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet 
Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. 
The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props'))" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/test/test.vcxproj.filters b/test/test.vcxproj.filters
new file mode 100644
index 0000000..2c50194
--- /dev/null
+++ b/test/test.vcxproj.filters
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="test_call_v8.cpp" />
+    <ClCompile Include="test_throw_ex.cpp" />
+    <ClCompile Include="test_factory.cpp" />
+    <ClCompile Include="test_convert.cpp" />
+    <ClCompile Include="test_class.cpp" />
+    <ClCompile Include="test_call_from_v8.cpp" />
+    <ClCompile Include="test_context.cpp" />
+    <ClCompile Include="test_property.cpp" />
+    <ClCompile Include="test_function.cpp" />
+    <ClCompile Include="test_module.cpp" />
+    <ClCompile Include="test_object.cpp" />
+    <ClCompile Include="test_json.cpp" />
+    <ClCompile Include="test_utility.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="test.hpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/test/test_call_from_v8.cpp b/test/test_call_from_v8.cpp
new file mode 100644
index 0000000..8a8e0d6
--- /dev/null
+++ b/test/test_call_from_v8.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/call_from_v8.hpp"
+#include "v8pp/context.hpp"
+#include "v8pp/function.hpp"
+
+#include "test.hpp"
+
+namespace {
+
+int x()
+{
+       return 0;
+}
+int y(int a)
+{
+       return a;
+}
+int z(v8::Isolate*, int a)
+{
+       return a;
+}
+
+void w(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       return args.GetReturnValue().Set(args.Length());
+}
+
+using v8pp::detail::select_call_traits;
+using v8pp::detail::call_from_v8_traits;
+using v8pp::detail::isolate_arg_call_traits;
+using v8pp::detail::v8_args_call_traits;
+
+static_assert(select_call_traits<decltype(&x)>::arg_count == 0, "x argc count");
+static_assert(std::is_same<select_call_traits<decltype(&x)>::arg_type<0>,
+       void>::value, "x has no args");
+
+static_assert(select_call_traits<decltype(&y)>::arg_count == 1, "y argc count");
+static_assert(std::is_same<select_call_traits<decltype(&y)>::arg_type<0>,
+       int>::value, "y 1st arg");
+
+static_assert(select_call_traits<decltype(&z)>::arg_count == 1, "z argc count");
+static_assert(std::is_same<select_call_traits<decltype(&z)>::arg_type<0>,
+       v8::Isolate*>::value, "z 1st arg");
+static_assert(std::is_same<select_call_traits<decltype(&z)>::arg_type<1>,
+       int>::value, "z 2nd arg");
+
+static_assert(std::is_same<select_call_traits<decltype(&x)>,
+       call_from_v8_traits<decltype(&x) >> ::value, "");
+
+static_assert(std::is_same<select_call_traits<decltype(&z)>,
+       isolate_arg_call_traits<decltype(&z) >> ::value, "");
+
+static_assert(std::is_same<select_call_traits<decltype(&w)>,
+       v8_args_call_traits<decltype(&w) >> ::value, "");
+
+} // unnamed namespace
+
+void test_call_from_v8()
+{
+       v8pp::context context;
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+
+       context.set("x", v8pp::wrap_function(isolate, "x", &x));
+       context.set("y", v8pp::wrap_function(isolate, "y", &y));
+       context.set("z", v8pp::wrap_function(isolate, "z", &z));
+       context.set("w", v8pp::wrap_function(isolate, "w", &w));
+
+       check_eq("x", run_script<int>(context, "x()"), 0);
+       check_eq("y", run_script<int>(context, "y(1)"), 1);
+       check_eq("z", run_script<int>(context, "z(2)"), 2);
+       check_eq("w", run_script<int>(context, "w(2, 'd', true, null)"), 4);
+}
diff --git a/test/test_call_v8.cpp b/test/test_call_v8.cpp
new file mode 100644
index 0000000..d6182c1
--- /dev/null
+++ b/test/test_call_v8.cpp
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/call_v8.hpp"
+#include "v8pp/context.hpp"
+
+#include "test.hpp"
+
+static void v8_arg_count(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       args.GetReturnValue().Set(args.Length());
+}
+
+void test_call_v8()
+{
+       v8pp::context context;
+
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+       v8::Handle<v8::Function> fun = v8::Function::New(isolate, v8_arg_count);
+
+       check_eq("no args",
+               v8pp::call_v8(isolate, fun, fun)->Int32Value(), 0);
+       check_eq("1 arg",
+               v8pp::call_v8(isolate, fun, fun, 1)->Int32Value(), 1);
+       check_eq("2 args",
+               v8pp::call_v8(isolate, fun, fun, true, 2.2)->Int32Value(), 2);
+       check_eq("3 args",
+               v8pp::call_v8(isolate, fun, fun, 1, true, "abc")->Int32Value(), 3);
+}
diff --git a/test/test_class.cpp b/test/test_class.cpp
new file mode 100644
index 0000000..8770af2
--- /dev/null
+++ b/test/test_class.cpp
@@ -0,0 +1,177 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/class.hpp"
+#include "v8pp/property.hpp"
+
+#include "test.hpp"
+
+struct Xbase
+{
+       int var = 1;
+
+       int get() const { return var; }
+       void set(int v) { var = v; }
+
+       int prop() const { return var; }
+       void prop(int v) { var = v; }
+
+       int fun1(int x) { return var + x; }
+       int fun2(int x) const { return var + x; }
+       int fun3(int x) volatile { return var + x; }
+       int fun4(int x) const volatile { return var + x; }
+       static int static_fun(int x) { return x; }
+};
+
+struct X : Xbase
+{
+};
+
+struct Y : X
+{
+       static int instance_count;
+
+       explicit Y(int x) { var = x; ++instance_count; }
+       ~Y() { --instance_count; }
+};
+
+int Y::instance_count = 0;
+
+struct Z {};
+
+namespace v8pp {
+template<>
+struct factory<Y>
+{
+       static Y* create(v8::Isolate*, int x) { return new Y(x); }
+       static void destroy(v8::Isolate*, Y* object) { delete object; }
+};
+} // v8pp
+
+static int extern_fun(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       int x = args[0]->Int32Value();
+       X const* self = v8pp::class_<X>::unwrap_object(args.GetIsolate(), args.This());
+       if (self) x += self->var;
+       return x;
+}
+
+void test_class()
+{
+       v8pp::context context;
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+
+       using x_prop_get = int (X::*)() const;
+       using x_prop_set = void (X::*)(int);
+
+       v8pp::class_<X> X_class(isolate);
+       X_class
+               .ctor()
+               .set_const("konst", 99)
+               .set("var", &X::var)
+               .set("rprop", v8pp::property(&X::get))
+               .set("wprop", v8pp::property(&X::get, &X::set))
+               .set("wprop2", v8pp::property(
+                       static_cast<x_prop_get>(&X::prop),
+                       static_cast<x_prop_set>(&X::prop)))
+               .set("fun1", &X::fun1)
+               .set("fun2", &X::fun2)
+               .set("fun3", &X::fun3)
+               .set("fun4", &X::fun4)
+               .set("static_fun", &X::static_fun)
+               .set("static_lambda", [](int x) { return x + 3; })
+               .set("extern_fun", extern_fun)
+               ;
+
+       v8pp::class_<Y> Y_class(context.isolate());
+       Y_class
+               .inherit<X>()
+               .ctor<int>()
+               ;
+
+       check_ex<std::runtime_error>("already wrapped class X", [isolate]()
+       {
+               v8pp::class_<X> X_class(isolate);
+       });
+       check_ex<std::runtime_error>("already inherited class X", [isolate, &Y_class]()
+       {
+               Y_class.inherit<X>();
+       });
+       check_ex<std::runtime_error>("unwrapped class Z", [isolate]()
+       {
+               v8pp::class_<Z>::find_object(isolate, nullptr);
+       });
+
+       context
+               .set("X", X_class)
+               .set("Y", Y_class)
+               ;
+
+       check_eq("X object", run_script<int>(context, "x = new X(); x.konst + x.var"), 100);
+       check_eq("X::rprop", run_script<int>(context, "x = new X(); x.rprop"), 1);
+       check_eq("X::wprop", run_script<int>(context, "x = new X(); ++x.wprop"), 2);
+       check_eq("X::wprop2", run_script<int>(context, "x = new X(); ++x.wprop2"), 2);
+       check_eq("X::fun1(1)", run_script<int>(context, "x = new X(); x.fun1(1)"), 2);
+       check_eq("X::fun2(2)", run_script<int>(context, "x = new X(); x.fun2(2)"), 3);
+       check_eq("X::fun3(3)", run_script<int>(context, "x = new X(); x.fun3(3)"), 4);
+       check_eq("X::fun4(4)", run_script<int>(context, "x = new X(); x.fun4(4)"), 5);
+       check_eq("X::static_fun(1)", run_script<int>(context, "X.static_fun(1)"), 1);
+       check_eq("X::static_lambda(1)", run_script<int>(context, "X.static_lambda(1)"), 4);
+       check_eq("X::extern_fun(5)", run_script<int>(context, "x = new X(); x.extern_fun(5)"), 6);
+       check_eq("X::extern_fun(6)", run_script<int>(context, "X.extern_fun(6)"), 6);
+
+       check_eq("Y object", run_script<int>(context, "y = new Y(-100); y.konst + y.var"), -1);
+
+       Y y1(-1);
+       v8::Handle<v8::Object> y1_obj = v8pp::class_<Y>::reference_external(context.isolate(), &y1);
+       check("y1", v8pp::from_v8<Y*>(isolate, y1_obj) == &y1);
+       check("y1_obj", v8pp::to_v8(isolate, y1) == y1_obj);
+
+       Y* y2 = new Y(-2);
+       v8::Handle<v8::Object> y2_obj = v8pp::class_<Y>::import_external(context.isolate(), y2);
+       check("y2", v8pp::from_v8<Y*>(isolate, y2_obj) == y2);
+       check("y2_obj", v8pp::to_v8(isolate, y2) == y2_obj);
+
+       v8::Handle<v8::Object> y3_obj = v8pp::class_<Y>::create_object(context.isolate(), -3);
+       Y* y3 = v8pp::class_<Y>::unwrap_object(isolate, y3_obj);
+       check("y3", v8pp::from_v8<Y*>(isolate, y3_obj) == y3);
+       check("y3_obj", v8pp::to_v8(isolate, y3) == y3_obj);
+       check_eq("y3.var", y3->var, -3);
+
+       run_script<int>(context, "for (i = 0; i < 10; ++i) new Y(i); i");
+       check_eq("Y count", Y::instance_count, 10 + 4); // 10 + y + y1 + y2 + y3
+       run_script<int>(context, "y = null; 0");
+
+       v8pp::class_<Y>::unreference_external(isolate, &y1);
+       check("unref y1", v8pp::from_v8<Y*>(isolate, y1_obj) == nullptr);
+       check("unref y1_obj", v8pp::to_v8(isolate, &y1).IsEmpty());
+       y1_obj.Clear();
+       check_ex<std::runtime_error>("y1 unreferenced", [isolate, &y1]()
+       {
+               v8pp::to_v8(isolate, y1);
+       });
+
+       v8pp::class_<Y>::destroy_object(isolate, y2);
+       check("unref y2", v8pp::from_v8<Y*>(isolate, y2_obj) == nullptr);
+       check("unref y2_obj", v8pp::to_v8(isolate, y2).IsEmpty());
+       y2_obj.Clear();
+
+       v8pp::class_<Y>::destroy_object(isolate, y3);
+       check("unref y3", v8pp::from_v8<Y*>(isolate, y3_obj) == nullptr);
+       check("unref y3_obj", v8pp::to_v8(isolate, y3).IsEmpty());
+       y3_obj.Clear();
+
+       std::string const v8_flags = "--expose_gc";
+       v8::V8::SetFlagsFromString(v8_flags.data(), (int)v8_flags.length());
+       
context.isolate()->RequestGarbageCollectionForTesting(v8::Isolate::GarbageCollectionType::kFullGarbageCollection);
+
+       check_eq("Y count after GC", Y::instance_count, 1); // y1
+
+       v8pp::class_<Y>::destroy(isolate);
+}
diff --git a/test/test_context.cpp b/test/test_context.cpp
new file mode 100644
index 0000000..066050a
--- /dev/null
+++ b/test/test_context.cpp
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/context.hpp"
+
+#include "test.hpp"
+
+void test_context()
+{
+       v8pp::context context;
+
+       v8::HandleScope scope(context.isolate());
+       int const r = context.run_script("42")->Int32Value();
+       check_eq("run_script", r, 42);
+}
diff --git a/test/test_convert.cpp b/test/test_convert.cpp
new file mode 100644
index 0000000..a921cdd
--- /dev/null
+++ b/test/test_convert.cpp
@@ -0,0 +1,174 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/convert.hpp"
+#include "test.hpp"
+
+#include <list>
+#include <vector>
+#include <map>
+
+template<typename T>
+void test_conv(v8::Isolate* isolate, T value)
+{
+       v8::Local<v8::Value> v8_value = v8pp::to_v8(isolate, value);
+       auto const value2 = v8pp::from_v8<T>(isolate, v8_value);
+       check_eq(typeid(T).name(), value2, value);
+}
+
+template<typename Char, size_t N>
+void test_string_conv(v8::Isolate* isolate, Char const (&str)[N])
+{
+       std::basic_string<Char> const str2(str, 2);
+
+       test_conv(isolate, str[0]);
+       test_conv(isolate, str);
+
+       check_eq("string literal",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, str)), str);
+       check_eq("string literal2",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, str, 2)), str2);
+
+       Char const* ptr = str;
+       check_eq("string pointer",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, ptr)), str);
+       check_eq("string pointer2",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, ptr, 2)), str2);
+
+       Char const* empty = str + N - 1; // use last \0 in source string
+       check_eq("empty string literal",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, "")), empty);
+       check_eq("empty string literal0",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, "", 0)), empty);
+
+       check_eq("empty string pointer",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, empty)), empty);
+       check_eq("empty string pointer0",
+               v8pp::from_v8<Char const*>(isolate, v8pp::to_v8(isolate, empty, 0)), empty);
+}
+
+struct person
+{
+       std::string name;
+       int age;
+
+//for test framework
+       bool operator!=(person const& other) const
+       {
+               return name != other.name || age != other.age;
+       }
+
+       friend std::ostream& operator<<(std::ostream& os, person const& p)
+       {
+               return os << "person: " << p.name << " age: " << p.age;
+       }
+};
+
+namespace v8pp {
+
+template<>
+struct convert<person>
+{
+       using from_type = person;
+       using to_type = v8::Handle<v8::Object>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsObject();
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, person const& p)
+       {
+               v8::EscapableHandleScope scope(isolate);
+               v8::Local<v8::Object> obj = v8::Object::New(isolate);
+               obj->Set(v8pp::to_v8(isolate, "name"), v8pp::to_v8(isolate, p.name));
+               obj->Set(v8pp::to_v8(isolate, "age"), v8pp::to_v8(isolate, p.age));
+               /* Simpler after #include <v8pp/object.hpp>
+               set_option(isolate, obj, "name", p.name);
+               set_option(isolate, obj, "age", p.age);
+               */
+               return scope.Escape(obj);
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::runtime_error("excpected object");
+               }
+
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Object> obj = value.As<v8::Object>();
+
+               person result;
+               result.name = v8pp::from_v8<std::string>(isolate,
+                       obj->Get(v8pp::to_v8(isolate, "name")));
+               result.age = v8pp::from_v8<int>(isolate,
+                       obj->Get(v8pp::to_v8(isolate, "age")));
+               
+               /* Simpler after #include <v8pp/object.hpp>
+               get_option(isolate, obj, "name", result.name);
+               get_option(isolate, obj, "age", result.age);
+               */
+               return result;
+       }
+};
+
+} // v8pp
+
+void test_convert()
+{
+       v8pp::context context;
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+
+       test_conv(isolate, 1);
+       test_conv(isolate, 2.2);
+       test_conv(isolate, true);
+
+       enum old_enum { A = 1, B = 5, C = - 1 };
+       test_conv(isolate, B);
+
+       enum class new_enum { X = 'a', Y = 'b', Z = 'c' };
+       test_conv(isolate, new_enum::Z);
+
+       test_string_conv(isolate, "qaz");
+#ifdef WIN32
+       test_string_conv(isolate, L"qaz");
+#endif
+
+       using int_vector = std::vector<int>;
+
+       int_vector vector = { 1, 2, 3 };
+       test_conv(isolate, vector);
+
+       std::map<char, int> map = { { 'a', 1 }, { 'b', 2 }, { 'c', 3 } };
+       test_conv(isolate, map);
+
+       std::array<int, 3> array = { 1, 2, 3 };
+       test_conv(isolate, array);
+
+       check_ex<std::runtime_error>("wrong array length", [isolate, array]()
+       {
+               v8::Local<v8::Array> arr = v8pp::to_v8(isolate,
+                       std::array<int, 3>{ 1, 2, 3 });
+               v8pp::from_v8<std::array<int, 2>>(isolate, arr);
+       });
+
+       check_eq("initializer list to array",
+               v8pp::from_v8<int_vector>(isolate, v8pp::to_v8(isolate,
+               { 1, 2, 3 })), vector);
+
+       std::list<int> list = { 1, 2, 3 };
+       check_eq("pair of iterators to array", v8pp::from_v8<int_vector>(isolate,
+               v8pp::to_v8(isolate, list.begin(), list.end())), vector);
+
+       person p;
+       p.name = "Al"; p.age = 33;
+       test_conv(isolate, p);
+}
diff --git a/test/test_factory.cpp b/test/test_factory.cpp
new file mode 100644
index 0000000..554942a
--- /dev/null
+++ b/test/test_factory.cpp
@@ -0,0 +1,117 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/factory.hpp"
+#include "v8pp/context.hpp"
+#include "v8pp/call_v8.hpp"
+
+#include "test.hpp"
+
+namespace {
+
+int ctor_types = 0;
+int ctor_count = 0;
+int dtor_count = 0;
+
+struct X
+{
+       X()
+       {
+               ++ctor_count;
+               ctor_types |= 0x01;
+       }
+
+       X(int) {
+               ++ctor_count;
+               ctor_types |= 0x02;
+       }
+
+       X(bool, float)
+       {
+               ++ctor_count;
+               ctor_types |= 0x04;
+       }
+
+       X(v8::FunctionCallbackInfo<v8::Value> const&)
+       {
+               ++ctor_count;
+               ctor_types |= 0x08;
+       }
+
+       ~X()
+       {
+               ++dtor_count;
+       }
+};
+
+class Y
+{
+public:
+       static Y* make(int) { return new Y; }
+       static void done(Y* y) { delete y; }
+private:
+       Y() {}
+       ~Y() {}
+};
+
+template<typename T, typename ...Args>
+void test_(v8::Isolate* isolate, Args&&... args)
+{
+       T* obj = v8pp::factory<T>::create(isolate, std::forward<Args>(args)...);
+       v8pp::factory<T>::destroy(isolate, obj);
+}
+
+void test_factories(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       v8::Isolate* isolate = args.GetIsolate();
+
+       ctor_types = ctor_count = dtor_count = 0;
+
+       test_<X>(isolate);
+       test_<X>(isolate, 1);
+       test_<X>(isolate, true, 1.0f);
+       test_<X>(isolate, args);
+
+       test_<Y>(isolate, 1);
+}
+
+} // unnamed namespace
+
+namespace v8pp {
+
+template<>
+struct factory<Y>
+{
+       static Y* create(v8::Isolate*, int arg)
+       {
+               ++ctor_count;
+               return Y::make(arg);
+       }
+
+       static void destroy(v8::Isolate*, Y* object)
+       {
+               Y::done(object);
+               ++dtor_count;
+       }
+};
+
+} // v8pp
+
+void test_factory()
+{
+       v8pp::context context;
+
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+       v8::Handle<v8::Function> fun = v8::Function::New(isolate, test_factories);
+
+       v8pp::call_v8(isolate, fun, fun);
+       check_eq("all ctors called", ctor_types, 0x0F);
+       check_eq("ctor count", ctor_count, 5);
+       check_eq("dtor count", dtor_count, 5);
+}
diff --git a/test/test_function.cpp b/test/test_function.cpp
new file mode 100644
index 0000000..6f04020
--- /dev/null
+++ b/test/test_function.cpp
@@ -0,0 +1,54 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/function.hpp"
+#include "v8pp/context.hpp"
+
+#include "test.hpp"
+
+static int f(int const& x) { return x; }
+static std::string g(char const* s) { return s? s : ""; }
+static int h(v8::Isolate*, int x, int y) { return x + y; }
+
+struct X
+{
+       int operator()(int x) const { return -x; }
+};
+
+void test_function()
+{
+       v8pp::context context;
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+
+       context.set("f", v8pp::wrap_function(isolate, "f", &f));
+       check_eq("f", run_script<int>(context, "f(1)"), 1);
+
+       context.set("g", v8pp::wrap_function(isolate, "g", &g));
+       check_eq("g", run_script<std::string>(context, "g('abc')"), "abc");
+
+       context.set("h", v8pp::wrap_function(isolate, "h", &h));
+       check_eq("h", run_script<int>(context, "h(1, 2)"), 3);
+
+       int x = 1, y = 2;
+       auto lambda = [x, y](int z) { return x + y + z; };
+       context.set("lambda", v8pp::wrap_function(isolate, "lambda", lambda));
+       check_eq("lambda", run_script<int>(context, "lambda(3)"), 6);
+
+       auto lambda2 = [](){ return 99; };
+       context.set("lambda2", v8pp::wrap_function(isolate, "lambda2", lambda2));
+       check_eq("lambda2", run_script<int>(context, "lambda2()"), 99);
+
+       X xfun;
+       context.set("xfun", v8pp::wrap_function(isolate, "xfun", xfun));
+       check_eq("xfun", run_script<int>(context, "xfun(5)"), -5);
+
+       std::function<int(int)> fun = f;
+       context.set("fun", v8pp::wrap_function(isolate, "fun", fun));
+       check_eq("fun", run_script<int>(context, "fun(42)"), 42);
+}
diff --git a/test/test_json.cpp b/test/test_json.cpp
new file mode 100644
index 0000000..2711593
--- /dev/null
+++ b/test/test_json.cpp
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/json.hpp"
+#include "v8pp/context.hpp"
+#include "v8pp/object.hpp"
+
+#include "test.hpp"
+
+void test_json()
+{
+       v8pp::context context;
+       v8::Isolate* isolate = context.isolate();
+       v8::HandleScope scope(isolate);
+
+       v8::Local<v8::Value> v;
+       std::string str;
+
+       str = v8pp::json_str(isolate, v);
+       v = v8pp::json_parse(isolate, str);
+       check("empty string", str.empty());
+       check("empty parse", v.IsEmpty());
+
+       v = v8::Integer::New(isolate, 42);
+
+       str = v8pp::json_str(isolate, v);
+       v = v8pp::json_parse(isolate, "42");
+       check_eq("int string", str, "42");
+       check_eq("int parse", v->Int32Value(), 42);
+
+       v8::Local<v8::Object> obj = v8::Object::New(isolate);
+       v8pp::set_option(isolate, obj, "x", 1);
+       v8pp::set_option(isolate, obj, "y", 2.2);
+       v8pp::set_option(isolate, obj, "z", "abc");
+
+       str = v8pp::json_str(isolate, obj);
+       v = v8pp::json_parse(isolate, str);
+       check_eq("object string", str, R"({"x":1,"y":2.2,"z":"abc"})");
+       check_eq("object parse", v8pp::json_str(isolate, v), str);
+
+       v8::Local<v8::Array> arr = v8::Array::New(isolate, 1);
+       arr->Set(0, obj);
+
+       str = v8pp::json_str(isolate, arr);
+       v = v8pp::json_parse(isolate, str);
+       check_eq("array string", str, R"([{"x":1,"y":2.2,"z":"abc"}])");
+       check_eq("array parse", v8pp::json_str(isolate, v), str);
+
+       v = v8pp::json_parse(isolate, "blah-blah");
+       check("parse error", v->IsNativeError());
+}
diff --git a/test/test_module.cpp b/test/test_module.cpp
new file mode 100644
index 0000000..74d7be8
--- /dev/null
+++ b/test/test_module.cpp
@@ -0,0 +1,71 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/module.hpp"
+#include "v8pp/context.hpp"
+#include "v8pp/property.hpp"
+
+#include "test.hpp"
+
+static std::string var;
+
+static int fun(int x) { return x + 1; }
+
+static int x = 1;
+static int get_x() { return x + 1; }
+static void set_x(int v) { x = v - 1; }
+
+void test_module()
+{
+       v8pp::context context;
+
+       v8::HandleScope scope(context.isolate());
+
+       v8pp::module module(context.isolate());
+       v8pp::module consts(context.isolate());
+
+       consts
+               .set_const("bool", true)
+               .set_const("char", 'Z')
+               .set_const("int", 100)
+               .set_const("str", "str")
+               .set_const("num", 99.9)
+               ;
+
+       module
+               .set("consts", consts)
+               .set("var", var)
+               .set("fun", &fun)
+               .set("empty", v8::Null(context.isolate()))
+               .set("rprop", v8pp::property(get_x))
+               .set("wprop", v8pp::property(get_x, set_x))
+               ;
+       context.set("module", module);
+
+       check_eq("module.consts.bool",
+               run_script<bool>(context, "module.consts.bool"), true);
+       check_eq("module.consts.char",
+               run_script<char>(context, "module.consts.char"), 'Z');
+       check_eq("module.consts.int",
+               run_script<char>(context, "module.consts.int"), 100);
+       check_eq("module.consts.str",
+               run_script<std::string>(context, "module.consts.str"), "str");
+
+       check_eq("module.var", run_script<std::string>(context,
+               "module.var = 'test'; module.var"), "test");
+       check_eq("var", var, "test");
+
+       check_eq("module.fun",
+               run_script<int>(context, "module.fun(100)"), 101);
+
+       check_eq("module.rprop",
+               run_script<int>(context, "module.rprop"), 2);
+       check_eq("module.wrop",
+               run_script<int>(context, "++module.wprop"), 3);
+       check_eq("x", x, 2);
+}
diff --git a/test/test_object.cpp b/test/test_object.cpp
new file mode 100644
index 0000000..1e17c5c
--- /dev/null
+++ b/test/test_object.cpp
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/object.hpp"
+
+#include "test.hpp"
+
+void test_object()
+{
+       v8pp::context context;
+       v8::Isolate* isolate = context.isolate();
+
+       v8::HandleScope scope(isolate);
+
+       v8::Local<v8::Object> obj = v8::Object::New(isolate);
+
+       v8pp::set_option(isolate, obj, "a", 10);
+       v8pp::set_option(isolate, obj, "b", true);
+       v8pp::set_option(isolate, obj, "sub", v8::Object::New(isolate));
+       v8pp::set_option(isolate, obj, "sub.x", "zzz");
+       v8pp::set_const(isolate, obj, "pi", 3.1415926);
+
+       int a;
+       check("get obj.a", v8pp::get_option(isolate, obj, "a", a));
+       check_eq("obj.a", a, 10);
+
+       bool b;
+       check("get obj.b", v8pp::get_option(isolate, obj, "b", b));
+       check_eq("obj.b", b, true);
+
+       std::string x;
+       check("get obj.sub.x", v8pp::get_option(isolate, obj, "sub.x", x));
+       check_eq("obj.sub.x", x, "zzz");
+
+       double pi;
+       check("get obj.pi", v8pp::get_option(isolate, obj, "pi", pi));
+       check("obj.pi", abs(pi - 3.1415926) < 10e-6);
+
+       v8::Local<v8::Object> sub;
+       check("get obj.sub", v8pp::get_option(isolate, obj, "sub", sub)
+               && sub->IsObject());
+
+       context.run_script("test = { test : function() { return 1; } }");
+       obj = isolate->GetCurrentContext()->Global();
+       v8::Local<v8::Function> fun;
+       check("test.test", v8pp::get_option(isolate, obj, "test.test", fun)
+               && fun->IsFunction());
+}
diff --git a/test/test_property.cpp b/test/test_property.cpp
new file mode 100644
index 0000000..3f02972
--- /dev/null
+++ b/test/test_property.cpp
@@ -0,0 +1,109 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/property.hpp"
+#include "v8pp/context.hpp"
+
+#include "test.hpp"
+
+namespace {
+
+int get1();
+void set1(int);
+
+int get2(v8::Isolate*);
+void set2(v8::Isolate*, int);
+
+void get3(v8::Local<v8::String> name,
+       v8::PropertyCallbackInfo<v8::Value> const& info);
+void set3(v8::Local<v8::String> name, v8::Local<v8::Value> value,
+       v8::PropertyCallbackInfo<void> const& info);
+
+struct X
+{
+       bool get1() const;
+       void set1(int);
+
+       bool get2(v8::Isolate*);
+       void set2(v8::Isolate*, int);
+
+       void get3(v8::Local<v8::String> name,
+               v8::PropertyCallbackInfo<v8::Value> const& info);
+       void set3(v8::Local<v8::String> name, v8::Local<v8::Value> value,
+               v8::PropertyCallbackInfo<void> const& info);
+};
+
+using namespace v8pp::detail;
+
+//property metafunctions
+static_assert(is_getter<decltype(&get1)>::value,
+       "getter function");
+static_assert(is_getter<decltype(&X::get1)>::value,
+       "getter member function");
+
+static_assert(is_setter<decltype(&set1)>::value,
+       "setter function");
+static_assert(is_setter<decltype(&X::set1)>::value,
+       "setter member function");
+
+static_assert(is_isolate_getter<decltype(&get2)>::value,
+       "isolate getter function");
+static_assert(is_isolate_getter<decltype(&X::get2)>::value,
+       "isolate getter member function");
+
+static_assert(is_isolate_setter<decltype(&set2)>::value,
+       "isolate setter function");
+static_assert(is_isolate_setter<decltype(&X::set2)>::value,
+       "isolate setter member function");
+
+static_assert(is_direct_getter<decltype(&get3)>::value,
+       "direct getter function");
+static_assert(is_direct_getter<decltype(&X::get3)>::value,
+       "direct getter member function");
+
+static_assert(is_direct_setter<decltype(&set3)>::value,
+       "direct setter function");
+static_assert(is_direct_setter<decltype(&X::set3)>::value,
+       "direct setter member function");
+
+// tag selectors
+static_assert(std::is_same<select_getter_tag<decltype(&get1)>,
+       getter_tag>::value, "getter function tag");
+static_assert(std::is_same<select_getter_tag<decltype(&X::get1)>,
+       getter_tag>::value, "getter member function tag");
+
+static_assert(std::is_same<select_setter_tag<decltype(&set1)>,
+       setter_tag>::value, "setter function tag");
+static_assert(std::is_same<select_setter_tag<decltype(&X::set1)>,
+       setter_tag>::value, "setter member function tag");
+
+static_assert(std::is_same<select_getter_tag<decltype(&get2)>,
+       isolate_getter_tag>::value, "isolate getter function tag");
+static_assert(std::is_same<select_getter_tag<decltype(&X::get2)>,
+       isolate_getter_tag>::value, "isolate getter member function tag");
+
+static_assert(std::is_same<select_setter_tag<decltype(&set2)>,
+       isolate_setter_tag>::value, "isolate setter function tag");
+static_assert(std::is_same<select_setter_tag<decltype(&X::set2)>,
+       isolate_setter_tag>::value, "isolate setter member function tag");
+
+static_assert(std::is_same<select_getter_tag<decltype(&get3)>,
+       direct_getter_tag>::value, "direct getter function tag");
+static_assert(std::is_same<select_getter_tag<decltype(&X::get3)>,
+       direct_getter_tag>::value, "direct getter member function tag");
+
+static_assert(std::is_same<select_setter_tag<decltype(&set3)>,
+       direct_setter_tag>::value, "direct setter function tag");
+static_assert(std::is_same<select_setter_tag<decltype(&X::set3)>,
+       direct_setter_tag>::value, "direct setter member function tag");
+
+} // unnamed namespace
+
+void test_property()
+{
+}
diff --git a/test/test_throw_ex.cpp b/test/test_throw_ex.cpp
new file mode 100644
index 0000000..b8b8eb8
--- /dev/null
+++ b/test/test_throw_ex.cpp
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/throw_ex.hpp"
+#include "test.hpp"
+
+namespace {
+
+void test(v8pp::context& context, std::string const& type,
+       v8::Local<v8::Value>(*exception_ctor)(v8::Handle<v8::String>))
+{
+       v8::Isolate* isolate = context.isolate();
+
+       v8::HandleScope scope(isolate);
+
+       v8::TryCatch try_catch;
+       v8::Local<v8::Value> ex = v8pp::throw_ex(isolate,
+               "exception message", exception_ctor);
+       check(" has caught", try_catch.HasCaught());
+       check("the same stack trace", try_catch.Message()
+               ->GetStackTrace() == v8::Exception::GetStackTrace(ex));
+       v8::String::Utf8Value err_msg(try_catch.Message()->Get());
+       check_eq("message", *err_msg, "Uncaught " + type + ": exception message");
+}
+
+} // unnamed namespace
+
+void test_throw_ex()
+{
+       v8pp::context context;
+       test(context, "Error",  v8::Exception::Error);
+       test(context, "RangeError", v8::Exception::RangeError);
+       test(context, "ReferenceError", v8::Exception::ReferenceError);
+       test(context, "SyntaxError", v8::Exception::SyntaxError);
+       test(context, "TypeError", v8::Exception::TypeError);
+}
diff --git a/test/test_utility.cpp b/test/test_utility.cpp
new file mode 100644
index 0000000..c062808
--- /dev/null
+++ b/test/test_utility.cpp
@@ -0,0 +1,218 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <functional>
+#include <v8.h>
+
+#include "v8pp/utility.hpp"
+#include "test.hpp"
+
+namespace {
+
+template<typename Ret, typename F>
+void test_ret(F&&)
+{
+       using R = typename v8pp::detail::function_traits<F>::return_type;
+       static_assert(std::is_same<Ret, R>::value, "wrong return_type");
+}
+
+template<typename ArgsTuple, typename F>
+void test_args(F&&)
+{
+       using Args = typename v8pp::detail::function_traits<F>::arguments;
+       static_assert(std::is_same<ArgsTuple, Args>::value, "wrong arguments");
+}
+
+template<typename Ret, typename Derived, typename F>
+void test_ret_derived(F&& f)
+{
+       using G = typename v8pp::detail::function_traits<F>::template pointer_type<Derived>;
+       test_ret<Ret, G>(std::forward<F>(f));
+}
+
+template<typename ArgsTuple, typename Derived, typename F>
+void test_args_derived(F&& f)
+{
+       using G = typename v8pp::detail::function_traits<F>::template pointer_type<Derived>;
+       test_args<ArgsTuple, G>(std::forward<F>(f));
+}
+
+void x() {}
+int y(int, float) { return 1; }
+
+void test_function_traits()
+{
+       test_ret<void>(x);
+       test_args<std::tuple<>>(x);
+
+       test_ret<int>(y);
+       test_args<std::tuple<int, float>>(y);
+
+       std::function<bool (int, char, float)> z;
+       test_ret<bool>(z);
+       test_args<std::tuple<int, char, float>>(z);
+
+       auto lambda = [](int, bool) -> char { return 'z'; };
+       test_ret<char>(lambda);
+       test_args<std::tuple<int, bool>>(lambda);
+
+       struct X
+       {
+               float f() const { return 0; }
+               void g(int) {}
+               int h(float, char) volatile { return 0; }
+               char i(float) const volatile { return 0; }
+               void operator()(int, char&) const volatile {}
+
+               float w;
+               const int x = 1;
+               volatile char y;
+               const volatile bool z = true;
+               mutable volatile short zz;
+       };
+
+       test_ret<float>(&X::f);
+       test_args<std::tuple<X const&>>(&X::f);
+
+       test_ret<void>(&X::g);
+       test_args<std::tuple<X&, int>>(&X::g);
+
+       test_ret<int>(&X::h);
+       test_args<std::tuple<X volatile&, float, char>>(&X::h);
+
+       test_ret<char>(&X::i);
+       test_args<std::tuple<X const volatile&, float>>(&X::i);
+
+       test_ret<void>(X());
+       test_args<std::tuple<int, char&>>(X());
+
+       test_ret<float>(&X::w);
+       test_args<std::tuple<X&>>(&X::w);
+
+       test_ret<int>(&X::x);
+       test_args<std::tuple<X const&>>(&X::x);
+
+       test_ret<char>(&X::y);
+       test_args<std::tuple<X volatile&>>(&X::y);
+
+       test_ret<bool>(&X::z);
+       test_args<std::tuple<X const volatile&>>(&X::z);
+
+       test_ret<short>(&X::zz);
+       test_args<std::tuple<X volatile&>>(&X::zz);
+
+       struct Y : X {};
+
+       test_ret_derived<float, Y>(&Y::f);
+       test_args_derived<std::tuple<Y const&>, Y>(&Y::f);
+
+       test_ret_derived<void, Y>(&Y::g);
+       test_args_derived<std::tuple<Y&, int>, Y>(&Y::g);
+
+       test_ret_derived<int, Y>(&Y::h);
+       test_args_derived<std::tuple<Y volatile&, float, char>, Y>(&Y::h);
+
+       test_ret_derived<char, Y>(&Y::i);
+       test_args_derived<std::tuple<Y const volatile&, float>, Y>(&Y::i);
+
+       test_ret_derived<float, Y>(&Y::w);
+       test_args_derived<std::tuple<Y&>, Y>(&Y::w);
+
+       test_ret_derived<int, Y>(&Y::x);
+       test_args_derived<std::tuple<Y const&>, Y>(&Y::x);
+
+       test_ret_derived<char, Y>(&Y::y);
+       test_args_derived<std::tuple<Y volatile&>, Y>(&Y::y);
+
+       test_ret_derived<bool, Y>(&Y::z);
+       test_args_derived<std::tuple<Y const volatile&>, Y>(&Y::z);
+
+       test_ret_derived<short, Y>(&Y::zz);
+       test_args_derived<std::tuple<Y volatile&>, Y>(&Y::zz);
+}
+
+void test_tuple_tail()
+{
+       using v8pp::detail::tuple_tail;
+
+       static_assert(std::is_same<tuple_tail<std::tuple<int>>::type,
+               std::tuple<>>::value, "");
+       static_assert(std::is_same<tuple_tail<std::tuple<int, char>>::type,
+               std::tuple<char>>::value, "");
+       static_assert(std::is_same<tuple_tail<std::tuple<int, char, bool>>::type,
+               std::tuple<char, bool>>::value, "");
+}
+
+int f() { return 1; }
+int g(int x) { return x; }
+int h(int x, bool) { return x; }
+
+struct Y
+{
+       int f() const { return 1; }
+};
+
+struct Z
+{
+       void operator()();
+};
+
+void test_apply_tuple()
+{
+       using v8pp::detail::apply_tuple;
+       using v8pp::detail::apply;
+
+       apply_tuple(f, std::make_tuple());
+       apply_tuple(g, std::make_tuple(1));
+       apply_tuple(h, std::make_tuple(1, true));
+       
+       check_eq("apply(f)", apply(f), 1);
+       check_eq("apply(g)", apply(g, 2), 2);
+       check_eq("apply(h)", apply(h, 3, true), 3);
+}
+
+void test_is_callable()
+{
+       using v8pp::detail::is_callable;
+
+       static_assert(is_callable<decltype(f)>::value, "f is callable");
+       static_assert(is_callable<decltype(g)>::value, "g is callable");
+       static_assert(is_callable<decltype(h)>::value, "h is callable");
+
+       auto lambda = [](){};
+       static_assert(is_callable<decltype(lambda)>::value, "lambda is callable");
+
+       static_assert(is_callable<Z>::value, "Z is callable");
+       static_assert(!is_callable<decltype(&Y::f)>::value, "Y::f is not callable");
+
+       static_assert(!is_callable<int>::value, "int is not callable");
+       static_assert(!is_callable<Y>::value, "Y is not callable");
+}
+
+} // unnamed namespace
+
+struct some_struct {};
+namespace test { class some_class {}; }
+
+void test_utility()
+{
+       test_apply_tuple();
+       test_is_callable();
+
+       using v8pp::detail::type_id;
+
+       check_eq("type_id", type_id<int>().name(), "int");
+       check_eq("type_id", type_id<bool>().name(), "bool");
+#ifdef _MSC_VER
+       check_eq("type_id", type_id<some_struct>().name(), "struct some_struct");
+       check_eq("type_id", type_id<test::some_class>().name(), "class test::some_class");
+#else
+       check_eq("type_id", type_id<some_struct>().name(), "some_struct");
+       check_eq("type_id", type_id<test::some_class>().name(), "test::some_class");
+#endif
+}
diff --git a/v8_options.gypi b/v8_options.gypi
new file mode 100644
index 0000000..2709537
--- /dev/null
+++ b/v8_options.gypi
@@ -0,0 +1,20 @@
+{
+    'variables': {
+        'component': 'shared_library',
+        'werror': '',
+        'v8_use_snapshot': 'false',
+        'v8_use_external_startup_data': 0,
+    },
+    'target_defaults': {
+        'configurations': {
+            'Debug': { 'msvs_settings':   { 'VCCLCompilerTool': { 'WarningLevel': '0', 'WarnAsError': 
'false' } } },
+            'Release': { 'msvs_settings': { 'VCCLCompilerTool': { 'WarningLevel': '0', 'WarnAsError': 
'false' } } },
+        },
+        'msvs_cygwin_shell': 0,
+        'target_conditions': [
+            ['_type=="static_library"', {
+                'standalone_static_library': 1,
+            }]
+       ],
+    },
+}
diff --git a/v8pp.sln b/v8pp.sln
new file mode 100644
index 0000000..a98748f
--- /dev/null
+++ b/v8pp.sln
@@ -0,0 +1,62 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8pp", "v8pp\v8pp.vcxproj", 
"{2E6CFC3D-5A08-4909-8D1A-3469063D169B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", 
"{69779536-9D04-48B2-B853-4E1B761A7A50}"
+       ProjectSection(ProjectDependencies) = postProject
+               {300469B1-31DA-4485-A75B-111C78697B16} = {300469B1-31DA-4485-A75B-111C78697B16}
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE} = {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "plugins\console.vcxproj", 
"{967D7CE6-8AD1-465C-A838-0A7E666DC1AE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file", "plugins\file.vcxproj", 
"{300469B1-31DA-4485-A75B-111C78697B16}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Debug|x64 = Debug|x64
+               Release|Win32 = Release|Win32
+               Release|x64 = Release|x64
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Debug|Win32.ActiveCfg = Debug|Win32
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Debug|Win32.Build.0 = Debug|Win32
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Debug|x64.ActiveCfg = Debug|x64
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Debug|x64.Build.0 = Debug|x64
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Release|Win32.ActiveCfg = Release|Win32
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Release|Win32.Build.0 = Release|Win32
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Release|x64.ActiveCfg = Release|x64
+               {2E6CFC3D-5A08-4909-8D1A-3469063D169B}.Release|x64.Build.0 = Release|x64
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Debug|Win32.ActiveCfg = Debug|Win32
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Debug|Win32.Build.0 = Debug|Win32
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Debug|x64.ActiveCfg = Debug|x64
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Debug|x64.Build.0 = Debug|x64
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Release|Win32.ActiveCfg = Release|Win32
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Release|Win32.Build.0 = Release|Win32
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Release|x64.ActiveCfg = Release|x64
+               {69779536-9D04-48B2-B853-4E1B761A7A50}.Release|x64.Build.0 = Release|x64
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Debug|Win32.ActiveCfg = Debug|Win32
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Debug|Win32.Build.0 = Debug|Win32
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Debug|x64.ActiveCfg = Debug|x64
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Debug|x64.Build.0 = Debug|x64
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Release|Win32.ActiveCfg = Release|Win32
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Release|Win32.Build.0 = Release|Win32
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Release|x64.ActiveCfg = Release|x64
+               {967D7CE6-8AD1-465C-A838-0A7E666DC1AE}.Release|x64.Build.0 = Release|x64
+               {300469B1-31DA-4485-A75B-111C78697B16}.Debug|Win32.ActiveCfg = Debug|Win32
+               {300469B1-31DA-4485-A75B-111C78697B16}.Debug|Win32.Build.0 = Debug|Win32
+               {300469B1-31DA-4485-A75B-111C78697B16}.Debug|x64.ActiveCfg = Debug|x64
+               {300469B1-31DA-4485-A75B-111C78697B16}.Debug|x64.Build.0 = Debug|x64
+               {300469B1-31DA-4485-A75B-111C78697B16}.Release|Win32.ActiveCfg = Release|Win32
+               {300469B1-31DA-4485-A75B-111C78697B16}.Release|Win32.Build.0 = Release|Win32
+               {300469B1-31DA-4485-A75B-111C78697B16}.Release|x64.ActiveCfg = Release|x64
+               {300469B1-31DA-4485-A75B-111C78697B16}.Release|x64.Build.0 = Release|x64
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/v8pp/call_from_v8.hpp b/v8pp/call_from_v8.hpp
new file mode 100644
index 0000000..092279a
--- /dev/null
+++ b/v8pp/call_from_v8.hpp
@@ -0,0 +1,185 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_CALL_FROM_V8_HPP_INCLUDED
+#define V8PP_CALL_FROM_V8_HPP_INCLUDED
+
+#include <functional>
+
+#include <v8.h>
+
+#include "v8pp/convert.hpp"
+#include "v8pp/utility.hpp"
+
+namespace v8pp { namespace detail {
+
+template<typename F, size_t Offset = 0>
+struct call_from_v8_traits
+{
+       static bool const is_mem_fun = std::is_member_function_pointer<F>::value;
+       using arguments = typename function_traits<F>::arguments;
+
+       static size_t const arg_count =
+               std::tuple_size<arguments>::value - is_mem_fun - Offset;
+
+       template<size_t Index, bool>
+       struct tuple_element
+       {
+               using type = typename std::tuple_element<Index, arguments>::type;
+       };
+
+       template<size_t Index>
+       struct tuple_element<Index, false>
+       {
+               using type = void;
+       };
+
+       template<size_t Index>
+       using arg_type = typename tuple_element<Index + is_mem_fun,
+               Index < (arg_count + Offset)>::type;
+
+       template<size_t Index>
+       using convert_type = decltype(convert<arg_type<Index>>::from_v8(
+               std::declval<v8::Isolate*>(), std::declval<v8::Handle<v8::Value>>()));
+
+       template<size_t Index>
+       static convert_type<Index>
+       arg_from_v8(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               return convert<arg_type<Index>>::from_v8(args.GetIsolate(), args[Index - Offset]);
+       }
+
+       static void check(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               if (args.Length() != arg_count)
+               {
+                       throw std::runtime_error("argument count does not match function definition");
+               }
+       }
+};
+
+template<typename F>
+using isolate_arg_call_traits = call_from_v8_traits<F, 1>;
+
+template<typename F, size_t Offset = 0>
+struct v8_args_call_traits : call_from_v8_traits<F, Offset>
+{
+       template<size_t Index>
+       using arg_type = v8::FunctionCallbackInfo<v8::Value> const&;
+
+       template<size_t Index>
+       using convert_type = v8::FunctionCallbackInfo<v8::Value> const&;
+
+       template<size_t Index>
+       static v8::FunctionCallbackInfo<v8::Value> const&
+       arg_from_v8(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               return args;
+       }
+
+       static void check(v8::FunctionCallbackInfo<v8::Value> const&)
+       {
+       }
+};
+
+template<typename F>
+using isolate_v8_args_call_traits = v8_args_call_traits<F, 1>;
+
+template<typename F, size_t Offset>
+using is_direct_args = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == (Offset + 1) &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<Offset>,
+               v8::FunctionCallbackInfo<v8::Value> const&>::value>;
+
+template<typename F>
+using is_first_arg_isolate = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count != 0 &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<0>,
+               v8::Isolate*>::value>;
+
+template<typename F>
+using select_call_traits = typename std::conditional<is_first_arg_isolate<F>::value,
+       typename std::conditional<is_direct_args<F, 1>::value,
+               isolate_v8_args_call_traits<F>, isolate_arg_call_traits<F>>::type,
+       typename std::conditional<is_direct_args<F, 0>::value,
+               v8_args_call_traits<F>, call_from_v8_traits<F>>::type
+>::type;
+
+template<typename F, typename CallTraits, size_t ...Indices>
+typename function_traits<F>::return_type
+call_from_v8_impl(F&& func, v8::FunctionCallbackInfo<v8::Value> const& args,
+       CallTraits, index_sequence<Indices...>)
+{
+       return func(CallTraits::template arg_from_v8<Indices>(args)...);
+}
+
+template<typename T, typename F, typename CallTraits, size_t ...Indices>
+typename function_traits<F>::return_type
+call_from_v8_impl(T& obj, F&& func, v8::FunctionCallbackInfo<v8::Value> const& args,
+       CallTraits, index_sequence<Indices...>)
+{
+       return (obj.*func)(CallTraits::template arg_from_v8<Indices>(args)...);
+}
+
+template<typename F, size_t ...Indices>
+typename function_traits<F>::return_type
+call_from_v8_impl(F&& func, v8::FunctionCallbackInfo<v8::Value> const& args,
+       isolate_arg_call_traits<F>, index_sequence<Indices...>)
+{
+       return func(args.GetIsolate(),
+               isolate_arg_call_traits<F>::template arg_from_v8<Indices + 1>(args)...);
+}
+
+template<typename T, typename F, size_t ...Indices>
+typename function_traits<F>::return_type
+call_from_v8_impl(T& obj, F&& func, v8::FunctionCallbackInfo<v8::Value> const& args,
+       isolate_arg_call_traits<F>, index_sequence<Indices...>)
+{
+       return (obj.*func)(args.GetIsolate(),
+               isolate_arg_call_traits<F>::template arg_from_v8<Indices + 1>(args)...);
+}
+
+template<typename F, size_t ...Indices>
+typename function_traits<F>::return_type
+call_from_v8_impl(F&& func, v8::FunctionCallbackInfo<v8::Value> const& args,
+       isolate_v8_args_call_traits<F>, index_sequence<Indices...>)
+{
+       return func(args.GetIsolate(), args);
+}
+
+template<typename T, typename F, size_t ...Indices>
+typename function_traits<F>::return_type
+call_from_v8_impl(T& obj, F&& func, v8::FunctionCallbackInfo<v8::Value> const& args,
+       isolate_v8_args_call_traits<F>, index_sequence<Indices...>)
+{
+       return (obj.*func)(args.GetIsolate(), args);
+}
+
+template<typename F>
+typename function_traits<F>::return_type
+call_from_v8(F&& func, v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       using call_traits = select_call_traits<F>;
+       call_traits::check(args);
+       return call_from_v8_impl(std::forward<F>(func), args,
+               call_traits(), make_index_sequence<call_traits::arg_count>());
+}
+
+template<typename T, typename F>
+typename function_traits<F>::return_type
+call_from_v8(T& obj, F&& func, v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       using call_traits = select_call_traits<F>;
+       call_traits::check(args);
+       return call_from_v8_impl(obj, std::forward<F>(func), args,
+               call_traits(), make_index_sequence<call_traits::arg_count>());
+}
+
+}} // v8pp::detail
+
+#endif // V8PP_CALL_FROM_V8_HPP_INCLUDED
diff --git a/v8pp/call_v8.hpp b/v8pp/call_v8.hpp
new file mode 100644
index 0000000..aa2585c
--- /dev/null
+++ b/v8pp/call_v8.hpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_CALL_V8_HPP_INCLUDED
+#define V8PP_CALL_V8_HPP_INCLUDED
+
+#include <v8.h>
+
+#include "v8pp/convert.hpp"
+
+namespace v8pp {
+
+/// Call a V8 function, converting C++ arguments to v8::Value arguments
+/// @param isolate V8 isolate instance
+/// @param func  V8 function to call
+/// @param recv V8 object used as `this` in the function
+/// @param args...  C++ arguments to convert to JS arguments using to_v8
+template<typename ...Args>
+v8::Handle<v8::Value> call_v8(v8::Isolate* isolate, v8::Handle<v8::Function> func,
+       v8::Handle<v8::Value> recv, Args&&... args)
+{
+       v8::EscapableHandleScope scope(isolate);
+
+       int const arg_count = sizeof...(Args);
+       // +1 to allocate array for arg_count == 0
+       v8::Handle<v8::Value> v8_args[arg_count + 1] =
+       {
+               to_v8(isolate, std::forward<Args>(args))...
+       };
+
+       v8::Local<v8::Value> result = func->Call(recv, arg_count, v8_args);
+
+       return scope.Escape(result);
+}
+
+} // namespace v8pp
+
+#endif // V8PP_CALL_V8_HPP_INCLUDED
diff --git a/v8pp/class.hpp b/v8pp/class.hpp
new file mode 100644
index 0000000..84d19b4
--- /dev/null
+++ b/v8pp/class.hpp
@@ -0,0 +1,773 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_CLASS_HPP_INCLUDED
+#define V8PP_CLASS_HPP_INCLUDED
+
+#include <cstdio>
+
+#include <algorithm>
+#include <memory>
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
+
+#include "v8pp/config.hpp"
+#include "v8pp/factory.hpp"
+#include "v8pp/function.hpp"
+#include "v8pp/persistent.hpp"
+#include "v8pp/property.hpp"
+
+namespace v8pp {
+
+template<typename T>
+class class_;
+
+namespace detail {
+
+inline std::string class_name(type_info const& info)
+{
+       return "v8pp::class_<" + info.name() + '>';
+}
+
+inline std::string pointer_str(void const* ptr)
+{
+       std::string buf(sizeof(void*) * 2 + 3, 0); // +3 for 0x and \0 terminator
+       int const len = 
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+               sprintf_s(&buf[0], buf.size(), "%p", ptr);
+#else
+               snprintf(&buf[0], buf.size(), "%p", ptr);
+#endif
+       buf.resize(len < 0? 0 : len);
+       return buf;
+}
+
+class class_info
+{
+public:
+       explicit class_info(type_info const& type) : type_(type) {}
+       class_info(class_info const&) = delete;
+       class_info& operator=(class_info const&) = delete;
+       virtual ~class_info() = default;
+
+       type_info const& type() const { return type_; }
+
+       using cast_function = void* (*)(void* ptr);
+
+       void add_base(class_info* info, cast_function cast)
+       {
+               auto it = std::find_if(bases_.begin(), bases_.end(),
+                       [info](base_class_info const& base) { return base.info == info; });
+               if (it != bases_.end())
+               {
+                       //assert(false && "duplicated inheritance");
+                       throw std::runtime_error(class_name(type_)
+                               + " is already inherited from " + class_name(info->type_));
+               }
+               bases_.emplace_back(info, cast);
+               info->derivatives_.emplace_back(this);
+       }
+
+       bool cast(void*& ptr, type_info const& type) const
+       {
+               if (type == type_ || !ptr)
+               {
+                       return true;
+               }
+
+               // fast way - search a direct parent
+               for (base_class_info const& base : bases_)
+               {
+                       if (base.info->type_ == type)
+                       {
+                               ptr = base.cast(ptr);
+                               return true;
+                       }
+               }
+
+               // slower way - walk on hierarhy
+               for (base_class_info const& base : bases_)
+               {
+                       void* p = base.cast(ptr);
+                       if (base.info->cast(p, type))
+                       {
+                               ptr = p;
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       void add_object(void* object, persistent<v8::Object>&& handle)
+       {
+               auto it = objects_.find(object);
+               if (it != objects_.end())
+               {
+                       //assert(false && "duplicate object");
+                       throw std::runtime_error(class_name(type())
+                               + " duplicate object " + pointer_str(object));
+               }
+               objects_.emplace(object, std::move(handle));
+       }
+
+       void remove_object(v8::Isolate* isolate, void* object,
+               void (*destroy)(v8::Isolate* isolate, void* obj) = nullptr)
+       {
+               auto it = objects_.find(object);
+               assert(objects_.find(object) != objects_.end() && "no object");
+               if (it != objects_.end())
+               {
+                       if (!it->second.IsNearDeath())
+                       {
+                               // remove pointer to wrapped  C++ object from V8 Object
+                               // internal field to disable unwrapping for this V8 Object
+                               assert(to_local(isolate, it->second)
+                                       ->GetAlignedPointerFromInternalField(0) == object);
+                               to_local(isolate, it->second)
+                                       ->SetAlignedPointerInInternalField(0, nullptr);
+                       }
+                       it->second.Reset();
+                       if (destroy)
+                       {
+                               destroy(isolate, object);
+                       }
+                       objects_.erase(it);
+               }
+       }
+
+       void remove_objects(v8::Isolate* isolate,
+               void (*destroy)(v8::Isolate* isolate, void* obj))
+       {
+               for (auto& object : objects_)
+               {
+                       object.second.Reset();
+                       if (destroy)
+                       {
+                               destroy(isolate, object.first);
+                       }
+               }
+               objects_.clear();
+       }
+
+       v8::Local<v8::Object> find_object(v8::Isolate* isolate, void const* object) const
+       {
+               auto it = objects_.find(const_cast<void*>(object));
+               if (it != objects_.end())
+               {
+                       return to_local(isolate, it->second);
+               }
+
+               v8::Local<v8::Object> result;
+               for (class_info const* info : derivatives_)
+               {
+                       result = info->find_object(isolate, object);
+                       if (!result.IsEmpty()) break;
+               }
+               return result;
+       }
+
+private:
+       struct base_class_info
+       {
+               class_info* info;
+               cast_function cast;
+
+               base_class_info(class_info* info, cast_function cast)
+                       : info(info)
+                       , cast(cast)
+               {
+               }
+       };
+
+       type_info const type_;
+       std::vector<base_class_info> bases_;
+       std::vector<class_info*> derivatives_;
+
+       std::unordered_map<void*, persistent<v8::Object>> objects_;
+};
+
+template<typename T>
+class class_singleton;
+
+class class_singletons
+{
+public:
+       template<typename T>
+       static class_singleton<T>& add_class(v8::Isolate* isolate)
+       {
+               class_singletons* singletons = instance(add, isolate);
+               type_info const type = type_id<T>();
+               auto it = singletons->find(type);
+               if (it != singletons->classes_.end())
+               {
+                       //assert(false && "class already registred");
+                       throw std::runtime_error(class_name(type)
+                               + " is already exist in isolate " + pointer_str(isolate));
+               }
+               singletons->classes_.emplace_back(new class_singleton<T>(isolate, type));
+               return *static_cast<class_singleton<T>*>(singletons->classes_.back().get());
+       }
+
+       template<typename T>
+       static void remove_class(v8::Isolate* isolate)
+       {
+               class_singletons* singletons = instance(get, isolate);
+               if (singletons)
+               {
+                       type_info const type = type_id<T>();
+                       auto it = singletons->find(type);
+                       if (it != singletons->classes_.end())
+                       {
+                               singletons->classes_.erase(it);
+                               if (singletons->classes_.empty())
+                               {
+                                       instance(remove, isolate);
+                               }
+                       }
+               }
+       }
+
+       template<typename T>
+       static class_singleton<T>& find_class(v8::Isolate* isolate)
+       {
+               class_singletons* singletons = instance(get, isolate);
+               type_info const type = type_id<T>();
+               if (singletons)
+               {
+                       auto it = singletons->find(type);
+                       if (it != singletons->classes_.end())
+                       {
+                               return *static_cast<class_singleton<T>*>(it->get());
+                       }
+               }
+               //assert(false && "class not registered");
+               throw std::runtime_error(class_name(type)
+                       + " not found in isolate " + pointer_str(isolate));
+       }
+
+       static void remove_all(v8::Isolate* isolate)
+       {
+               instance(remove, isolate);
+       }
+
+private:
+       using classes = std::vector<std::unique_ptr<class_info>>;
+       classes classes_;
+
+       classes::iterator find(type_info const& type)
+       {
+               return std::find_if(classes_.begin(), classes_.end(),
+                       [&type](std::unique_ptr<class_info> const& info)
+                       {
+                               return info->type() == type;
+                       });
+       }
+
+       enum operation { get, add, remove };
+       static class_singletons* instance(operation op, v8::Isolate* isolate)
+       {
+#if defined(V8PP_ISOLATE_DATA_SLOT)
+               class_singletons* instances = static_cast<class_singletons*>(
+                       isolate->GetData(V8PP_ISOLATE_DATA_SLOT));
+               switch (op)
+               {
+               case get:
+                       return instances;
+               case add:
+                       if (!instances)
+                       {
+                               instances = new class_singletons;
+                               isolate->SetData(V8PP_ISOLATE_DATA_SLOT, instances);
+                       }
+                       return instances;
+               case remove:
+                       if (instances)
+                       {
+                               delete instances;
+                               isolate->SetData(V8PP_ISOLATE_DATA_SLOT, nullptr);
+                       }
+               default:
+                       return nullptr;
+               }
+#else
+               static std::unordered_map<v8::Isolate*, class_singletons> instances;
+               switch (op)
+               {
+               case get:
+                       {
+                               auto it = instances.find(isolate);
+                               return it != instances.end()? &it->second : nullptr;
+                       }
+               case add:
+                       return &instances[isolate];
+               case remove:
+                       instances.erase(isolate);
+               default:
+                       return nullptr;
+               }
+#endif
+       }
+};
+
+template<typename T>
+class class_singleton : public class_info
+{
+public:
+       class_singleton(v8::Isolate* isolate, type_info const& type)
+               : class_info(type)
+               , isolate_(isolate)
+       {
+               v8::Local<v8::FunctionTemplate> func = v8::FunctionTemplate::New(isolate_);
+               v8::Local<v8::FunctionTemplate> js_func = v8::FunctionTemplate::New(isolate_,
+                       [](v8::FunctionCallbackInfo<v8::Value> const& args)
+               {
+                       v8::Isolate* isolate = args.GetIsolate();
+                       try
+                       {
+                               return args.GetReturnValue().Set(
+                                       class_singletons::find_class<T>(isolate).wrap_object(args));
+                       }
+                       catch (std::exception const& ex)
+                       {
+                               args.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+                       }
+               });
+
+               func_.Reset(isolate_, func);
+               js_func_.Reset(isolate_, js_func);
+
+               // each JavaScript instance has 2 internal fields:
+               //  0 - pointer to a wrapped C++ object
+               //  1 - pointer to the class_singleton
+               func->InstanceTemplate()->SetInternalFieldCount(2);
+
+               // no class constructor available by default
+               ctor_ = nullptr;
+               // use destructor from factory<T>::destroy()
+               dtor_ = [](v8::Isolate* isolate, void* obj)
+               {
+                       factory<T>::destroy(isolate, static_cast<T*>(obj));
+               };
+
+               func->Inherit(js_func);
+       }
+
+       class_singleton(class_singleton const&) = delete;
+       class_singleton& operator=(class_singleton const&) = delete;
+
+       ~class_singleton()
+       {
+               destroy_objects();
+       }
+
+       v8::Handle<v8::Object> wrap(T* object, bool destroy_after)
+       {
+               v8::EscapableHandleScope scope(isolate_);
+
+               v8::Local<v8::Object> obj = class_function_template()
+                                            ->GetFunction()->NewInstance 
(v8::Isolate::GetCurrent()->GetCurrentContext())
+                                            .FromMaybe(v8::Local<v8::Object>());
+               obj->SetAlignedPointerInInternalField(0, object);
+               obj->SetAlignedPointerInInternalField(1, this);
+
+               persistent<v8::Object> pobj(isolate_, obj);
+               if (destroy_after)
+               {
+                       pobj.SetWeak(object,
+#ifdef V8_USE_WEAK_CB_INFO
+                               [](v8::WeakCallbackInfo<T> const& data)
+#else
+                               [](v8::WeakCallbackData<v8::Object, T> const& data)
+#endif
+                       {
+                               v8::Isolate* isolate = data.GetIsolate();
+                               T* object = data.GetParameter();
+                               class_singletons::find_class<T>(isolate).destroy_object(object);
+                       }
+#ifdef V8_USE_WEAK_CB_INFO
+                               , v8::WeakCallbackType::kParameter
+#endif
+                               );
+               }
+               else
+               {
+                       pobj.SetWeak(object,
+#ifdef V8_USE_WEAK_CB_INFO
+                               [](v8::WeakCallbackInfo<T> const& data)
+#else
+                               [](v8::WeakCallbackData<v8::Object, T> const& data)
+#endif
+                       {
+                               v8::Isolate* isolate = data.GetIsolate();
+                               T* object = data.GetParameter();
+                               class_singletons::find_class<T>(isolate)
+                                       .remove_object(isolate, object);
+                       }
+#ifdef V8_USE_WEAK_CB_INFO
+                               , v8::WeakCallbackType::kParameter
+#endif
+                               );
+
+               }
+
+               class_info::add_object(object, std::move(pobj));
+
+               return scope.Escape(obj);
+       }
+
+       v8::Isolate* isolate() { return isolate_; }
+
+       v8::Local<v8::FunctionTemplate> class_function_template()
+       {
+               return to_local(isolate_, func_);
+       }
+
+       v8::Local<v8::FunctionTemplate> js_function_template()
+       {
+               return to_local(isolate_, js_func_);
+       }
+
+       template<typename ...Args>
+       void ctor()
+       {
+               ctor_ = [](v8::FunctionCallbackInfo<v8::Value> const& args)
+               {
+                       using ctor_type = T* (*)(v8::Isolate* isolate, Args...);
+                       return call_from_v8(static_cast<ctor_type>(&factory<T>::create), args);
+               };
+       }
+
+       template<typename U>
+       void inherit()
+       {
+               class_singleton<U>* base = &class_singletons::find_class<U>(isolate_);
+               add_base(base, [](void* ptr) -> void*
+                       {
+                               return static_cast<U*>(static_cast<T*>(ptr));
+                       });
+               js_function_template()->Inherit(base->class_function_template());
+       }
+
+       v8::Handle<v8::Object> wrap_external_object(T* object)
+       {
+               return wrap(object, false);
+       }
+
+       v8::Handle<v8::Object> wrap_object(T* object)
+       {
+               return wrap(object, true);
+       }
+
+       v8::Handle<v8::Object> wrap_object(v8::FunctionCallbackInfo<v8::Value> const& args)
+       {
+               if (!ctor_)
+               {
+                       //assert(false && "create not allowed");
+                       throw std::runtime_error(class_name(type()) + " has no constructor");
+               }
+               return wrap_object(ctor_(args));
+       }
+
+       T* unwrap_object(v8::Local<v8::Value> value)
+       {
+               v8::HandleScope scope(isolate_);
+
+               while (value->IsObject())
+               {
+                       v8::Handle<v8::Object> obj = value->ToObject();
+                       if (obj->InternalFieldCount() == 2)
+                       {
+                               void* ptr = obj->GetAlignedPointerFromInternalField(0);
+                               class_info* info = static_cast<class_info*>(
+                                       obj->GetAlignedPointerFromInternalField(1));
+                               if (info && info->cast(ptr, type()))
+                               {
+                                       return static_cast<T*>(ptr);
+                               }
+                       }
+                       value = obj->GetPrototype();
+               }
+               return nullptr;
+       }
+
+       v8::Handle<v8::Object> find_object(T const* obj)
+       {
+               return class_info::find_object(isolate_, obj);
+       }
+
+       void destroy_objects()
+       {
+               class_info::remove_objects(isolate_, dtor_);
+       }
+
+       void destroy_object(T* obj)
+       {
+               class_info::remove_object(isolate_, obj, dtor_);
+       }
+
+private:
+       v8::Isolate* isolate_;
+       T* (*ctor_)(v8::FunctionCallbackInfo<v8::Value> const& args);
+       void (*dtor_)(v8::Isolate*, void*);
+
+       v8::UniquePersistent<v8::FunctionTemplate> func_;
+       v8::UniquePersistent<v8::FunctionTemplate> js_func_;
+};
+
+} // namespace detail
+
+/// Interface for registering C++ classes in V8
+template<typename T>
+class class_
+{
+       using class_singleton = detail::class_singleton<T>;
+       detail::class_singleton<T>& class_singleton_;
+public:
+       explicit class_(v8::Isolate* isolate)
+               : class_singleton_(detail::class_singletons::add_class<T>(isolate))
+       {
+       }
+
+       /// Set class constructor signature
+       template<typename ...Args>
+       class_& ctor()
+       {
+               class_singleton_.template ctor<Args...>();
+               return *this;
+       }
+
+       /// Inhert from C++ class U
+       template<typename U>
+       class_& inherit()
+       {
+               static_assert(std::is_base_of<U, T>::value, "Class U should be base for class T");
+               //TODO: std::is_convertible<T*, U*> and check for duplicates in hierarchy?
+               class_singleton_.template inherit<U>();
+               return *this;
+       }
+
+       /// Set C++ class member function
+       template<typename Method>
+       typename std::enable_if<
+               std::is_member_function_pointer<Method>::value, class_&>::type
+       set(char const *name, Method mem_func)
+       {
+               using mem_func_type =
+                       typename detail::function_traits<Method>::template pointer_type<T>;
+
+               class_singleton_.class_function_template()->PrototypeTemplate()->Set(
+                       isolate(), name, wrap_function_template(isolate(),
+                               static_cast<mem_func_type>(mem_func)));
+               return *this;
+       }
+
+       /// Set static class function
+       template<typename Function,
+               typename Func = typename std::decay<Function>::type>
+       typename std::enable_if<detail::is_callable<Func>::value, class_&>::type
+       set(char const *name, Function&& func)
+       {
+               v8::Local<v8::Data> wrapped_fun =
+                       wrap_function_template(isolate(), std::forward<Func>(func));
+               class_singleton_.class_function_template()
+                       ->PrototypeTemplate()->Set(isolate(), name, wrapped_fun);
+               class_singleton_.js_function_template()->Set(isolate(), name, wrapped_fun);
+               return *this;
+       }
+
+       /// Set class member data
+       template<typename Attribute>
+       typename std::enable_if<
+               std::is_member_object_pointer<Attribute>::value, class_&>::type
+       set(char const *name, Attribute attribute, bool readonly = false)
+       {
+               v8::HandleScope scope(isolate());
+
+               using attribute_type = typename
+                       detail::function_traits<Attribute>::template pointer_type<T>;
+               v8::AccessorGetterCallback getter = &member_get<attribute_type>;
+               v8::AccessorSetterCallback setter = &member_set<attribute_type>;
+               if (readonly)
+               {
+                       setter = nullptr;
+               }
+
+               class_singleton_.class_function_template()->PrototypeTemplate()
+                       ->SetAccessor(v8pp::to_v8(isolate(), name), getter, setter,
+                               detail::set_external_data(isolate(),
+                                       std::forward<Attribute>(attribute)), v8::DEFAULT,
+                               v8::PropertyAttribute(v8::DontDelete | (setter? 0 : v8::ReadOnly)));
+               return *this;
+       }
+
+       /// Set class attribute with getter and setter
+       template<typename GetMethod, typename SetMethod>
+       typename std::enable_if<std::is_member_function_pointer<GetMethod>::value
+               && std::is_member_function_pointer<SetMethod>::value, class_&>::type
+       set(char const *name, property_<GetMethod, SetMethod>&& prop)
+       {
+               using prop_type = property_<GetMethod, SetMethod>;
+
+               v8::HandleScope scope(isolate());
+
+               using property_type = property_<
+                       typename detail::function_traits<GetMethod>::template pointer_type<T>,
+                       typename detail::function_traits<SetMethod>::template pointer_type<T>
+               >;
+               v8::AccessorGetterCallback getter = property_type::get;
+               v8::AccessorSetterCallback setter = property_type::set;
+               if (prop_type::is_readonly)
+               {
+                       setter = nullptr;
+               }
+
+               class_singleton_.class_function_template()->PrototypeTemplate()
+                       ->SetAccessor(v8pp::to_v8(isolate(), name),getter, setter,
+                               detail::set_external_data(isolate(),
+                                       std::forward<prop_type>(prop)), v8::DEFAULT,
+                               v8::PropertyAttribute(v8::DontDelete | (setter ? 0 : v8::ReadOnly)));
+               return *this;
+       }
+
+       /// Set value as a read-only property
+       template<typename Value>
+       class_& set_const(char const* name, Value const& value)
+       {
+               v8::HandleScope scope(isolate());
+
+               class_singleton_.class_function_template()->PrototypeTemplate()
+                       ->Set(v8pp::to_v8(isolate(), name), to_v8(isolate(), value),
+                               v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+               return *this;
+       }
+
+       /// v8::Isolate where the class bindings belongs
+       v8::Isolate* isolate() { return class_singleton_.isolate(); }
+
+       v8::Local<v8::FunctionTemplate> class_function_template()
+       {
+               return class_singleton_.class_function_template();
+       }
+
+       v8::Local<v8::FunctionTemplate> js_function_template()
+       {
+               return class_singleton_.js_function_template();
+       }
+
+       /// Create JavaScript object which references externally created C++ class.
+       /// It will not take ownership of the C++ pointer.
+       static v8::Handle<v8::Object> reference_external(v8::Isolate* isolate, T* ext)
+       {
+               return detail::class_singletons::find_class<T>(isolate)
+                       .wrap_external_object(ext);
+       }
+
+       /// Remove external reference from JavaScript
+       static void unreference_external(v8::Isolate* isolate, T* ext)
+       {
+               return detail::class_singletons::find_class<T>(isolate)
+                       .remove_object(isolate, ext);
+       }
+
+       /// As reference_external but delete memory for C++ object
+       /// when JavaScript object is deleted. You must use "new" to allocate ext.
+       static v8::Handle<v8::Object> import_external(v8::Isolate* isolate, T* ext)
+       {
+               return detail::class_singletons::find_class<T>(isolate)
+                       .wrap_object(ext);
+       }
+
+       /// Get wrapped object from V8 value, may return nullptr on fail.
+       static T* unwrap_object(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               return detail::class_singletons::find_class<T>(isolate)
+                       .unwrap_object(value);
+       }
+
+       /// Create a wrapped C++ object and import it into JavaScript
+       template<typename ...Args>
+       static v8::Handle<v8::Object> create_object(v8::Isolate* isolate, Args... args)
+       {
+               T* obj = v8pp::factory<T>::create(isolate, std::forward<Args>(args)...);
+               return import_external(isolate, obj);
+       }
+
+       /// Find V8 object handle for a wrapped C++ object, may return empty handle on fail.
+       static v8::Handle<v8::Object> find_object(v8::Isolate* isolate, T const* obj)
+       {
+               return detail::class_singletons::find_class<T>(isolate)
+                       .find_object(obj);
+       }
+
+       /// Destroy wrapped C++ object
+       static void destroy_object(v8::Isolate* isolate, T* obj)
+       {
+               detail::class_singletons::find_class<T>(isolate).destroy_object(obj);
+       }
+
+       /// Destroy all wrapped C++ objects of this class
+       static void destroy_objects(v8::Isolate* isolate)
+       {
+               detail::class_singletons::find_class<T>(isolate).destroy_objects();
+       }
+
+       /// Destroy all wrapped C++ objects and this binding class_
+       static void destroy(v8::Isolate* isolate)
+       {
+               detail::class_singletons::remove_class<T>(isolate);
+       }
+
+private:
+       template<typename Attribute>
+       static void member_get(v8::Local<v8::String>,
+               v8::PropertyCallbackInfo<v8::Value> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               try
+               {
+                       T const& self = v8pp::from_v8<T const&>(isolate, info.This());
+                       Attribute attr = detail::get_external_data<Attribute>(info.Data());
+                       info.GetReturnValue().Set(to_v8(isolate, self.*attr));
+               }
+               catch (std::exception const& ex)
+               {
+                       info.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+               }
+       }
+
+       template<typename Attribute>
+       static void member_set(v8::Local<v8::String>, v8::Local<v8::Value> value,
+               v8::PropertyCallbackInfo<void> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               try
+               {
+                       T& self = v8pp::from_v8<T&>(isolate, info.This());
+                       Attribute ptr = detail::get_external_data<Attribute>(info.Data());
+                       using attr_type = typename detail::function_traits<Attribute>::return_type;
+                       self.*ptr = v8pp::from_v8<attr_type>(isolate, value);
+               }
+               catch (std::exception const& ex)
+               {
+                       info.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+               }
+       }
+};
+
+inline void cleanup(v8::Isolate* isolate)
+{
+       detail::class_singletons::remove_all(isolate);
+}
+
+} // namespace v8pp
+
+#endif // V8PP_CLASS_HPP_INCLUDED
diff --git a/v8pp/config.hpp b/v8pp/config.hpp
new file mode 100644
index 0000000..b295692
--- /dev/null
+++ b/v8pp/config.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_CONFIG_HPP_INCLUDED
+#define V8PP_CONFIG_HPP_INCLUDED
+
+/// v8::Isolate data slot number, used in v8pp for shared data
+//#if !defined(V8PP_ISOLATE_DATA_SLOT)
+//#define V8PP_ISOLATE_DATA_SLOT 0
+//#endif
+
+/// v8pp plugin initialization procedure name
+#if !defined(V8PP_PLUGIN_INIT_PROC_NAME)
+#define V8PP_PLUGIN_INIT_PROC_NAME v8pp_module_init
+#endif
+
+/// v8pp plugin filename suffix
+#if !defined(V8PP_PLUGIN_SUFFIX)
+       #if defined(WIN32)
+       #define V8PP_PLUGIN_SUFFIX ".dll"
+       #else
+       #define V8PP_PLUGIN_SUFFIX ".so"
+       #endif
+#endif
+
+#if defined(_MSC_VER)
+       #define V8PP_EXPORT __declspec(dllexport)
+       #define V8PP_IMPORT __declspec(dllimport)
+#elif __GNUC__ >= 4
+       #define V8PP_EXPORT __attribute__((__visibility__("default")))
+       #define V8PP_IMPORT V8PP_EXPORT
+#else
+       #define V8PP_EXPORT
+       #define V8PP_IMPORT
+#endif
+
+#define V8PP_PLUGIN_INIT(isolate) extern "C" V8PP_EXPORT \
+v8::Handle<v8::Value> V8PP_PLUGIN_INIT_PROC_NAME(isolate)
+
+#endif // V8PP_CONFIG_HPP_INCLUDED
diff --git a/v8pp/context.cpp b/v8pp/context.cpp
new file mode 100644
index 0000000..b29ab43
--- /dev/null
+++ b/v8pp/context.cpp
@@ -0,0 +1,267 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "v8pp/context.hpp"
+#include "v8pp/config.hpp"
+#include "v8pp/convert.hpp"
+#include "v8pp/function.hpp"
+#include "v8pp/module.hpp"
+#include "v8pp/class.hpp"
+#include "v8pp/throw_ex.hpp"
+
+#include <fstream>
+
+#if defined(WIN32)
+#include <windows.h>
+static char const path_sep = '\\';
+#else
+#include <dlfcn.h>
+static char const path_sep = '/';
+#endif
+
+#define STRINGIZE(s) STRINGIZE0(s)
+#define STRINGIZE0(s) #s
+
+namespace v8pp {
+
+struct context::dynamic_module
+{
+       void* handle;
+       v8::UniquePersistent<v8::Value> exports;
+
+       dynamic_module() = default;
+       dynamic_module(dynamic_module&& other)
+               : handle(other.handle)
+               , exports(std::move(other.exports))
+       {
+               other.handle = nullptr;
+       }
+
+       dynamic_module(dynamic_module const&) = delete;
+};
+
+void context::load_module(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       v8::Isolate* isolate = args.GetIsolate();
+
+       v8::EscapableHandleScope scope(isolate);
+       v8::Local<v8::Value> result;
+       try
+       {
+               std::string const name = from_v8<std::string>(isolate, args[0], "");
+               if (name.empty())
+               {
+                       throw std::runtime_error("load_module: require module name string argument");
+               }
+
+               context* ctx = detail::get_external_data<context*>(args.Data());
+               context::dynamic_modules::iterator it = ctx->modules_.find(name);
+
+               // check if module is already loaded
+               if (it != ctx->modules_.end())
+               {
+                       result = v8::Local<v8::Value>::New(isolate, it->second.exports);
+               }
+               else
+               {
+                       std::string filename = name;
+                       if (!ctx->lib_path_.empty())
+                       {
+                               filename = ctx->lib_path_ + path_sep + name;
+                       }
+                       std::string const suffix = V8PP_PLUGIN_SUFFIX;
+                       if (filename.size() >= suffix.size()
+                               && filename.compare(filename.size() - suffix.size(), suffix.size(), suffix) 
!= 0)
+                       {
+                               filename += suffix;
+                       }
+
+                       dynamic_module module;
+#if defined(WIN32)
+                       UINT const prev_error_mode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
+                       module.handle = LoadLibraryA(filename.c_str());
+                       ::SetErrorMode(prev_error_mode);
+#else
+                       module.handle = dlopen(filename.c_str(), RTLD_LAZY);
+#endif
+
+                       if (!module.handle)
+                       {
+                               throw std::runtime_error("load_module(" + name
+                                       + "): could not load shared library " + filename);
+                       }
+#if defined(WIN32)
+                       void *sym = ::GetProcAddress((HMODULE)module.handle,
+                               STRINGIZE(V8PP_PLUGIN_INIT_PROC_NAME));
+#else
+                       void *sym = dlsym(module.handle, STRINGIZE(V8PP_PLUGIN_INIT_PROC_NAME));
+#endif
+                       if (!sym)
+                       {
+                               throw std::runtime_error("load_module(" + name
+                                       + "): initialization function "
+                                       STRINGIZE(V8PP_PLUGIN_INIT_PROC_NAME)
+                                       " not found in " + filename);
+                       }
+
+                       using module_init_proc = v8::Handle<v8::Value>(*)(v8::Isolate*);
+                       module_init_proc init_proc = reinterpret_cast<module_init_proc>(sym);
+                       result = init_proc(isolate);
+                       module.exports.Reset(isolate, result);
+                       ctx->modules_.emplace(name, std::move(module));
+               }
+       }
+       catch (std::exception const& ex)
+       {
+               result = throw_ex(isolate, ex.what());
+       }
+       args.GetReturnValue().Set(scope.Escape(result));
+}
+
+void context::run_file(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       v8::Isolate* isolate = args.GetIsolate();
+
+       v8::EscapableHandleScope scope(isolate);
+       v8::Local<v8::Value> result;
+       try
+       {
+               std::string const filename = from_v8<std::string>(isolate, args[0], "");
+               if (filename.empty())
+               {
+                       throw std::runtime_error("run_file: require filename string argument");
+               }
+
+               context* ctx = detail::get_external_data<context*>(args.Data());
+               result = to_v8(isolate, ctx->run_file(filename));
+       }
+       catch (std::exception const& ex)
+       {
+               result = throw_ex(isolate, ex.what());
+       }
+       args.GetReturnValue().Set(scope.Escape(result));
+}
+
+struct array_buffer_allocator : v8::ArrayBuffer::Allocator
+{
+       void* Allocate(size_t length)
+       {
+               return calloc(length, 1);
+       }
+       void* AllocateUninitialized(size_t length)
+       {
+               return malloc(length);
+       }
+       void Free(void* data, size_t length)
+       {
+               free(data); (void)length;
+       }
+};
+static array_buffer_allocator array_buffer_allocator_;
+
+context::context(v8::Isolate* isolate, v8::ArrayBuffer::Allocator* allocator)
+{
+       own_isolate_ = (isolate == nullptr);
+       if (own_isolate_)
+       {
+               v8::Isolate::CreateParams create_params;
+               create_params.array_buffer_allocator =
+                       allocator ? allocator : &array_buffer_allocator_;
+
+               isolate = v8::Isolate::New(create_params);
+               isolate->Enter();
+       }
+       isolate_ = isolate;
+
+       v8::HandleScope scope(isolate_);
+
+       v8::Handle<v8::Value> data = detail::set_external_data(isolate_, this);
+       v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+
+       global->Set(isolate_, "require",
+               v8::FunctionTemplate::New(isolate_, context::load_module, data));
+       global->Set(isolate_, "run",
+               v8::FunctionTemplate::New(isolate_, context::run_file, data));
+
+       v8::Handle<v8::Context> impl = v8::Context::New(isolate_, nullptr, global);
+       impl->Enter();
+       impl_.Reset(isolate_, impl);
+}
+
+context::~context()
+{
+       // remove all class singletons before modules unload
+       cleanup(isolate_);
+
+       for (auto& kv : modules_)
+       {
+               dynamic_module& module = kv.second;
+               module.exports.Reset();
+               if (module.handle)
+               {
+#if defined(WIN32)
+                       ::FreeLibrary((HMODULE)module.handle);
+#else
+                       dlclose(module.handle);
+#endif
+               }
+       }
+       modules_.clear();
+
+       v8::Local<v8::Context> impl = to_local(isolate_, impl_);
+       impl->Exit();
+
+       impl_.Reset();
+       if (own_isolate_)
+       {
+               isolate_->Exit();
+               isolate_->Dispose();
+       }
+}
+
+context& context::set(char const* name, v8::Handle<v8::Value> value)
+{
+       v8::HandleScope scope(isolate_);
+       to_local(isolate_, impl_)->Global()->Set(to_v8(isolate_, name), value);
+       return *this;
+}
+
+context& context::set(char const* name, module& m)
+{
+       return set(name, m.new_instance());
+}
+
+v8::Handle<v8::Value> context::run_file(std::string const& filename)
+{
+       std::ifstream stream(filename.c_str());
+       if (!stream)
+       {
+               throw std::runtime_error("could not locate file " + filename);
+       }
+
+       std::istreambuf_iterator<char> begin(stream), end;
+       return run_script(std::string(begin, end), filename);
+}
+
+v8::Handle<v8::Value> context::run_script(std::string const& source,
+       std::string const& filename)
+{
+       v8::EscapableHandleScope scope(isolate_);
+
+       v8::Local<v8::Script> script = v8::Script::Compile(
+               to_v8(isolate_, source), to_v8(isolate_, filename));
+
+       v8::Local<v8::Value> result;
+       if (!script.IsEmpty())
+       {
+               result = script->Run();
+       }
+       return scope.Escape(result);
+}
+
+} // namespace v8pp
diff --git a/v8pp/context.hpp b/v8pp/context.hpp
new file mode 100644
index 0000000..1db4a3e
--- /dev/null
+++ b/v8pp/context.hpp
@@ -0,0 +1,86 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_CONTEXT_HPP_INCLUDED
+#define V8PP_CONTEXT_HPP_INCLUDED
+
+#include <string>
+#include <map>
+
+#include <v8.h>
+
+#include "v8pp/convert.hpp"
+
+namespace v8pp {
+
+class module;
+
+template<typename T>
+class class_;
+
+/// V8 isolate and context wrapper
+class context
+{
+public:
+       /// Create context with optional existing v8::Isolate
+       /// and v8::ArrayBuffer::Allocator
+       explicit context(v8::Isolate* isolate = nullptr,
+               v8::ArrayBuffer::Allocator* allocator = nullptr);
+       ~context();
+
+       /// V8 isolate associated with this context
+       v8::Isolate* isolate() { return isolate_; }
+
+       /// Library search path
+       std::string const& lib_path() const { return lib_path_; }
+
+       /// Set new library search path
+       void set_lib_path(std::string const& lib_path) { lib_path_ = lib_path; }
+
+       /// Run script file, returns script result
+       /// or empty handle on failure, use v8::TryCatch around it to find out why.
+       /// Must be invoked in a v8::HandleScope
+       v8::Handle<v8::Value> run_file(std::string const& filename);
+
+       /// The same as run_file but uses string as the script source
+       v8::Handle<v8::Value> run_script(std::string const& source,
+               std::string const& filename = "");
+
+       /// Set a V8 value in the context global object with specified name
+       context& set(char const* name, v8::Handle<v8::Value> value);
+
+       /// Set module to the context global object
+       context& set(char const *name, module& m);
+
+       /// Set class to the context global object
+       template<typename T>
+       context& set(char const* name, class_<T>& cl)
+       {
+               v8::HandleScope scope(isolate_);
+               cl.class_function_template()->SetClassName(v8pp::to_v8(isolate_, name));
+               return set(name, cl.js_function_template()->GetFunction());
+       }
+
+private:
+       bool own_isolate_;
+       v8::Isolate* isolate_;
+       v8::Persistent<v8::Context> impl_;
+
+       struct dynamic_module;
+       using dynamic_modules = std::map<std::string, dynamic_module>;
+
+       static void load_module(v8::FunctionCallbackInfo<v8::Value> const& args);
+       static void run_file(v8::FunctionCallbackInfo<v8::Value> const& args);
+
+       dynamic_modules modules_;
+       std::string lib_path_;
+};
+
+} // namespace v8pp
+
+#endif // V8PP_CONTEXT_HPP_INCLUDED
diff --git a/v8pp/convert.hpp b/v8pp/convert.hpp
new file mode 100644
index 0000000..b0ab77a
--- /dev/null
+++ b/v8pp/convert.hpp
@@ -0,0 +1,685 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_CONVERT_HPP_INCLUDED
+#define V8PP_CONVERT_HPP_INCLUDED
+
+#include <v8.h>
+
+#include <climits>
+#include <string>
+#include <array>
+#include <vector>
+#include <map>
+#include <iterator>
+#include <stdexcept>
+#include <type_traits>
+#include <typeinfo>
+
+namespace v8pp {
+
+template<typename T>
+class class_;
+
+// Generic convertor
+template<typename T, typename Enable = void>
+struct convert;
+/*
+{
+       using from_type = T;
+       using to_type = v8::Handle<v8::Value>;
+
+       static bool is_valid(v8::Isolate* isolate, v8::Handle<v8::Value> value);
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value);
+       static to_type to_v8(v8::Isolate* isolate, T const& value);
+};
+*/
+
+// converter specializations for string types
+template<typename Char, typename Traits, typename Alloc>
+struct convert<std::basic_string<Char, Traits, Alloc>>
+{
+       static_assert(sizeof(Char) <= sizeof(uint16_t),
+               "only UTF-8 and UTF-16 strings are supported");
+
+       using from_type = std::basic_string<Char, Traits, Alloc>;
+       using to_type = v8::Handle<v8::String>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsString();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected String");
+               }
+
+               if (sizeof(Char) == 1)
+               {
+                       v8::String::Utf8Value const str(value);
+                       return from_type(reinterpret_cast<Char const*>(*str), str.length());
+               }
+               else
+               {
+                       v8::String::Value const str(value);
+                       return from_type(reinterpret_cast<Char const*>(*str), str.length());
+               }
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, from_type const& value)
+       {
+               if (sizeof(Char) == 1)
+               {
+                       return v8::String::NewFromUtf8(isolate,
+                               reinterpret_cast<char const*>(value.data()),
+                               v8::String::kNormalString, static_cast<int>(value.length()));
+               }
+               else
+               {
+                       return v8::String::NewFromTwoByte(isolate,
+                               reinterpret_cast<uint16_t const*>(value.data()),
+                               v8::String::kNormalString, static_cast<int>(value.length()));
+               }
+       }
+};
+
+template<typename Char>
+struct convert<Char const*>
+{
+       static_assert(sizeof(Char) <= sizeof(uint16_t),
+               "only UTF-8 and UTF-16 strings are supported");
+
+
+       // A string that converts to Char const *
+       struct convertible_string : std::basic_string<Char>
+       {
+               convertible_string(Char const* str, size_t len)
+                       : std::basic_string<Char>(str, len) {}
+               operator Char const*() const { return this->c_str(); }
+       };
+
+       using from_type = convertible_string;
+       using to_type = v8::Handle<v8::String>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsString();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected String");
+               }
+
+               if (sizeof(Char) == 1)
+               {
+                       v8::String::Utf8Value const str(value);
+                       return from_type(reinterpret_cast<Char const*>(*str), str.length());
+               }
+               else
+               {
+                       v8::String::Value const str(value);
+                       return from_type(reinterpret_cast<Char const*>(*str), str.length());
+               }
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, Char const* value, size_t len = ~0)
+       {
+               if (sizeof(Char) == 1)
+               {
+                       return v8::String::NewFromUtf8(isolate,
+                               reinterpret_cast<char const*>(value),
+                               v8::String::kNormalString, static_cast<int>(len));
+               }
+               else
+               {
+                       return v8::String::NewFromTwoByte(isolate,
+                               reinterpret_cast<uint16_t const*>(value),
+                               v8::String::kNormalString, static_cast<int>(len));
+               }
+       }
+};
+
+// converter specializations for primitive types
+template<>
+struct convert<bool>
+{
+       using from_type = bool;
+       using to_type = v8::Handle<v8::Boolean>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsBoolean();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Boolean");
+               }
+               return value->ToBoolean()->Value();
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, bool value)
+       {
+               return v8::Boolean::New(isolate, value);
+       }
+};
+
+template<typename T>
+struct convert<T, typename std::enable_if<std::is_integral<T>::value>::type>
+{
+       using from_type = T;
+       using to_type = v8::Handle<v8::Number>;
+
+       enum { bits = sizeof(T) * CHAR_BIT, is_signed = std::is_signed<T>::value };
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsNumber();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Number");
+               }
+
+               if (bits <= 32)
+               {
+                       if (is_signed)
+                       {
+                               return static_cast<T>(value->Int32Value());
+                       }
+                       else
+                       {
+                               return static_cast<T>(value->Uint32Value());
+                       }
+               }
+               else
+               {
+                       return static_cast<T>(value->IntegerValue());
+               }
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, T value)
+       {
+               if (bits <= 32)
+               {
+                       if (is_signed)
+                       {
+                               return v8::Integer::New(isolate,
+                                       static_cast<int32_t>(value));
+                       }
+                       else
+                       {
+                               return v8::Integer::NewFromUnsigned(isolate,
+                                       static_cast<uint32_t>(value));
+                       }
+               }
+               else
+               {
+                       //TODO: check value < (1<<57) to fit in double?
+                       return v8::Number::New(isolate, static_cast<double>(value));
+               }
+       }
+};
+
+template<typename T>
+struct convert<T, typename std::enable_if<std::is_enum<T>::value>::type>
+{
+       using underlying_type = typename std::underlying_type<T>::type;
+
+       using from_type = T;
+       using to_type = typename convert<underlying_type>::to_type;
+
+       static bool is_valid(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               return convert<underlying_type>::is_valid(isolate, value);
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               return static_cast<T>(convert<underlying_type>::from_v8(isolate, value));
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, T value)
+       {
+               return convert<underlying_type>::to_v8(isolate,
+                       static_cast<underlying_type>(value));
+       }
+};
+
+template<typename T>
+struct convert<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
+{
+       using from_type = T;
+       using to_type = v8::Handle<v8::Number>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsNumber();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Number");
+               }
+
+               return static_cast<T>(value->NumberValue());
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, T value)
+       {
+               return v8::Number::New(isolate, value);
+       }
+};
+
+// convert Array <-> std::array
+template<typename T, size_t N>
+struct convert<std::array<T, N>>
+{
+       using from_type = std::array<T, N>;
+       using to_type = v8::Handle<v8::Array>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsArray();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Array");
+               }
+
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Array> array = value.As<v8::Array>();
+
+               if (array->Length() != N)
+               {
+                       throw std::runtime_error("Invalid array length: expected "
+                               + std::to_string(N) + " actual "
+                               + std::to_string(array->Length()));
+               }
+
+               from_type result;
+               for (uint32_t i = 0; i < N; ++i)
+               {
+                       result[i] = convert<T>::from_v8(isolate, array->Get(i));
+               }
+               return result;
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, from_type const& value)
+       {
+               v8::EscapableHandleScope scope(isolate);
+
+               v8::Local<v8::Array> result = v8::Array::New(isolate, N);
+               for (uint32_t i = 0; i < N; ++i)
+               {
+                       result->Set(i, convert<T>::to_v8(isolate, value[i]));
+               }
+               return scope.Escape(result);
+       }
+};
+
+// convert Array <-> std::vector
+template<typename T, typename Alloc>
+struct convert<std::vector<T, Alloc>>
+{
+       using from_type = std::vector<T, Alloc>;
+       using to_type = v8::Handle<v8::Array>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsArray();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Array");
+               }
+
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Array> array = value.As<v8::Array>();
+
+               from_type result;
+               result.reserve(array->Length());
+               for (uint32_t i = 0, count = array->Length(); i < count; ++i)
+               {
+                       result.emplace_back(convert<T>::from_v8(isolate, array->Get(i)));
+               }
+               return result;
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, from_type const& value)
+       {
+               v8::EscapableHandleScope scope(isolate);
+
+               uint32_t const size = static_cast<uint32_t>(value.size());
+               v8::Local<v8::Array> result = v8::Array::New(isolate, size);
+               for (uint32_t i = 0; i < size; ++i)
+               {
+                       result->Set(i, convert<T>::to_v8(isolate, value[i]));
+               }
+               return scope.Escape(result);
+       }
+};
+
+// convert Object <-> std::map
+template<typename Key, typename Value, typename Less, typename Alloc>
+struct convert<std::map<Key, Value, Less, Alloc>>
+{
+       using from_type = std::map<Key, Value, Less, Alloc>;
+       using to_type = v8::Handle<v8::Object>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsObject();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Object");
+               }
+
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Object> object = value.As<v8::Object>();
+               v8::Local<v8::Array> prop_names = object->GetPropertyNames();
+
+               from_type result;
+               for (uint32_t i = 0, count = prop_names->Length(); i < count; ++i)
+               {
+                       v8::Local<v8::Value> key = prop_names->Get(i);
+                       v8::Local<v8::Value> val = object->Get(key);
+                       result.emplace(convert<Key>::from_v8(isolate, key),
+                               convert<Value>::from_v8(isolate, val));
+               }
+               return result;
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, from_type const& value)
+       {
+               v8::EscapableHandleScope scope(isolate);
+
+               v8::Local<v8::Object> result = v8::Object::New(isolate);
+               for (auto const& item: value)
+               {
+                       result->Set(convert<Key>::to_v8(isolate, item.first),
+                               convert<Value>::to_v8(isolate, item.second));
+               }
+               return scope.Escape(result);
+       }
+};
+
+// converter specializations for V8 Handles
+template<typename T>
+struct convert<v8::Handle<T>, typename std::enable_if<
+       !std::is_same<v8::Handle<T>, v8::Local<T>>::value>::type>
+{
+       using from_type = v8::Handle<T>;
+       using to_type = v8::Handle<T>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.As<T>().IsEmpty();
+       }
+
+       static v8::Handle<T> from_v8(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return value.As<T>();
+       }
+
+       static v8::Handle<T> to_v8(v8::Isolate*, v8::Handle<T> value)
+       {
+               return value;
+       }
+};
+
+template<typename T>
+struct convert<v8::Local<T>>
+{
+       using from_type = v8::Handle<T>;
+       using to_type = v8::Handle<T>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.As<T>().IsEmpty();
+       }
+
+       static v8::Handle<T> from_v8(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return value.As<T>();
+       }
+
+       static v8::Handle<T> to_v8(v8::Isolate*, v8::Local<T> value)
+       {
+               return value;
+       }
+};
+
+template<typename T>
+struct convert<v8::Persistent<T>>
+{
+       using from_type = v8::Handle<T>;
+       using to_type = v8::Handle<T>;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.As<T>().IsEmpty();
+       }
+
+       static v8::Handle<T> from_v8(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return value.As<T>();
+       }
+
+       static v8::Handle<T> to_v8(v8::Isolate*, v8::Persistent<T> value)
+       {
+               return value;
+       }
+};
+
+template<typename T, typename Enable = void>
+struct is_wrapped_class;
+
+// convert specialization for wrapped user classes
+template<typename T>
+struct is_wrapped_class<T> : std::is_class<T> {};
+
+template<typename T>
+struct is_wrapped_class<v8::Handle<T>, typename std::enable_if<
+       !std::is_same<v8::Handle<T>, v8::Local<T>>::value>::type> : std::false_type{};
+
+template<typename T>
+struct is_wrapped_class<v8::Local<T>> : std::false_type {};
+
+template<typename T>
+struct is_wrapped_class<v8::Persistent<T>> : std::false_type {};
+
+template<typename Char, typename Traits, typename Alloc>
+struct is_wrapped_class<std::basic_string<Char, Traits, Alloc>> : std::false_type {};
+
+template<typename T, size_t N>
+struct is_wrapped_class<std::array<T, N>> : std::false_type{};
+
+template<typename T, typename Alloc>
+struct is_wrapped_class<std::vector<T, Alloc>> : std::false_type {};
+
+template<typename Key, typename Value, typename Less, typename Alloc>
+struct is_wrapped_class<std::map<Key, Value, Less, Alloc>> : std::false_type {};
+
+template<typename T>
+struct convert<T*, typename std::enable_if<is_wrapped_class<T>::value>::type>
+{
+       using from_type = T*;
+       using to_type = v8::Handle<v8::Object>;
+       using class_type = typename std::remove_cv<T>::type;
+
+       static bool is_valid(v8::Isolate*, v8::Handle<v8::Value> value)
+       {
+               return !value.IsEmpty() && value->IsObject();
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       return nullptr;
+               }
+               return class_<class_type>::unwrap_object(isolate, value);
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, T const* value)
+       {
+               return class_<class_type>::find_object(isolate, value);
+       }
+};
+
+template<typename T>
+struct convert<T, typename std::enable_if<is_wrapped_class<T>::value>::type>
+{
+       using from_type = T&;
+       using to_type = v8::Handle<v8::Object>;
+       using class_type = typename std::remove_cv<T>::type;
+
+       static bool is_valid(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               return convert<T*>::is_valid(isolate, value);
+       }
+
+       static from_type from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       {
+               if (!is_valid(isolate, value))
+               {
+                       throw std::invalid_argument("expected Object");
+               }
+               if (T* object = convert<T*>::from_v8(isolate, value))
+               {
+                       return *object;
+               }
+               throw std::runtime_error("failed to unwrap C++ object");
+       }
+
+       static to_type to_v8(v8::Isolate* isolate, T const& value)
+       {
+               v8::Handle<v8::Object> result = class_<class_type>::find_object(isolate, &value);
+               if (!result.IsEmpty()) return result;
+                class_type* obj = v8pp::factory<class_type>::create(isolate, value);
+               if (!obj) throw std::runtime_error("failed to wrap C++ object");
+               return class_<class_type>::import_external(isolate, obj);
+       }
+};
+
+template<typename T>
+struct convert<T&> : convert<T> {};
+
+template<typename T>
+struct convert<T const&> : convert<T> {};
+
+template<typename T>
+auto from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+       -> decltype(convert<T>::from_v8(isolate, value))
+{
+       return convert<T>::from_v8(isolate, value);
+}
+
+template<typename T, typename U>
+auto from_v8(v8::Isolate* isolate, v8::Handle<v8::Value> value,U const& default_value)
+       -> decltype(convert<T>::from_v8(isolate, value))
+{
+       return convert<T>::is_valid(isolate, value)?
+               convert<T>::from_v8(isolate, value) : default_value;
+}
+
+inline v8::Handle<v8::String> to_v8(v8::Isolate* isolate, char const* str, size_t len)
+{
+       return convert<char const*>::to_v8(isolate, str, len);
+}
+
+template<size_t N>
+v8::Handle<v8::String> to_v8(v8::Isolate* isolate,
+       char const (&str)[N], size_t len = N - 1)
+{
+       return convert<char const*>::to_v8(isolate, str, len);
+}
+
+#ifdef WIN32
+inline v8::Handle<v8::String> to_v8(v8::Isolate* isolate,
+       wchar_t const* str, size_t len)
+{
+       return convert<wchar_t const*>::to_v8(isolate, str, len);
+}
+
+template<size_t N>
+v8::Handle<v8::String> to_v8(v8::Isolate* isolate,
+       wchar_t const (&str)[N], size_t len = N - 1)
+{
+       return convert<wchar_t const*>::to_v8(isolate, str, len);
+}
+#endif
+
+template<typename T>
+auto to_v8(v8::Isolate* isolate, T const& value)
+       -> decltype(convert<T>::to_v8(isolate, value))
+{
+       return convert<T>::to_v8(isolate, value);
+}
+
+template<typename Iterator>
+v8::Handle<v8::Array> to_v8(v8::Isolate* isolate, Iterator begin, Iterator end)
+{
+       v8::EscapableHandleScope scope(isolate);
+
+       v8::Local<v8::Array> result = v8::Array::New(isolate);
+       for (uint32_t idx = 0; begin != end; ++begin, ++idx)
+       {
+               result->Set(idx, to_v8(isolate, *begin));
+       }
+       return scope.Escape(result);
+}
+
+template<typename T>
+v8::Handle<v8::Array> to_v8(v8::Isolate* isolate, std::initializer_list<T> const& init)
+{
+       return to_v8(isolate, init.begin(), init.end());
+}
+
+template<typename T>
+v8::Local<T> to_local(v8::Isolate* isolate, v8::PersistentBase<T> const& handle)
+{
+       if (handle.IsWeak())
+       {
+               return v8::Local<T>::New(isolate, handle);
+       }
+       else
+       {
+               return *reinterpret_cast<v8::Local<T>*>(
+                       const_cast<v8::PersistentBase<T>*>(&handle));
+       }
+}
+
+} // namespace v8pp
+
+#endif // V8PP_CONVERT_HPP_INCLUDED
diff --git a/v8pp/factory.hpp b/v8pp/factory.hpp
new file mode 100644
index 0000000..be3abe9
--- /dev/null
+++ b/v8pp/factory.hpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_FACTORY_HPP_INCLUDED
+#define V8PP_FACTORY_HPP_INCLUDED
+
+#include <utility>
+
+#include <v8.h>
+
+namespace v8pp {
+
+// Factory that calls C++ constructor
+template<typename T>
+struct factory
+{
+       static size_t const object_size = sizeof(T);
+
+       template<typename ...Args>
+       static T* create(v8::Isolate* isolate, Args... args)
+       {
+               T* object = new T(std::forward<Args>(args)...);
+               isolate->AdjustAmountOfExternalAllocatedMemory(
+                       static_cast<int64_t>(object_size));
+               return object;
+       }
+
+       static void destroy(v8::Isolate* isolate, T* object)
+       {
+               delete object;
+               isolate->AdjustAmountOfExternalAllocatedMemory(
+                       -static_cast<int64_t>(object_size));
+       }
+};
+
+} //namespace v8pp
+
+#endif // V8PP_FACTORY_HPP_INCLUDED
diff --git a/v8pp/function.hpp b/v8pp/function.hpp
new file mode 100644
index 0000000..4d848c2
--- /dev/null
+++ b/v8pp/function.hpp
@@ -0,0 +1,220 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_FUNCTION_HPP_INCLUDED
+#define V8PP_FUNCTION_HPP_INCLUDED
+
+#include <tuple>
+#include <type_traits>
+
+#include "v8pp/call_from_v8.hpp"
+#include "v8pp/throw_ex.hpp"
+#include "v8pp/utility.hpp"
+
+#if defined(V8_MAJOR_VERSION) && defined(V8_MINOR_VERSION) && defined(V8_BUILD_NUMBER) \
+      && (V8_MAJOR_VERSION > 4 || (V8_MAJOR_VERSION == 4 \
+      && (V8_MINOR_VERSION > 3 || (V8_MINOR_VERSION == 3 && V8_BUILD_NUMBER > 28))))
+#define V8_USE_WEAK_CB_INFO
+#endif
+
+
+namespace v8pp {
+
+namespace detail {
+
+template<typename T>
+using is_pointer_cast_allowed = std::integral_constant<bool,
+       sizeof(T) <= sizeof(void*) && std::is_trivial<T>::value>;
+
+template<typename T>
+union pointer_cast
+{
+private:
+       void* ptr;
+       T value;
+
+public:
+       static_assert(is_pointer_cast_allowed<T>::value, "pointer_cast is not allowed");
+
+       explicit pointer_cast(void* ptr) : ptr(ptr) {}
+       explicit pointer_cast(T value) : value(value) {}
+
+       operator void*() const { return ptr; }
+       operator T() const { return value; }
+};
+
+template<typename T>
+class external_data
+{
+public:
+       static v8::Local<v8::External> set(v8::Isolate* isolate, T&& data)
+       {
+               external_data* value = new external_data;
+               try
+               {
+                       new (value->storage()) T(std::forward<T>(data));
+               }
+               catch (...)
+               {
+                       delete value;
+                       throw;
+               }
+
+               v8::Local<v8::External> ext = v8::External::New(isolate, value);
+               value->pext_.Reset(isolate, ext);
+               value->pext_.SetWeak(value,
+#ifdef V8_USE_WEAK_CB_INFO
+                       [](v8::WeakCallbackInfo<external_data> const& data)
+#else
+                       [](v8::WeakCallbackData<v8::External, external_data> const& data)
+#endif
+               {
+                       delete data.GetParameter();
+               }
+#ifdef V8_USE_WEAK_CB_INFO
+                       , v8::WeakCallbackType::kParameter
+#endif
+                       );
+               return ext;
+       }
+
+       static T& get(v8::Local<v8::External> ext)
+       {
+               external_data* value = static_cast<external_data*>(ext->Value());
+               return *static_cast<T*>(value->storage());
+       }
+
+private:
+       void* storage() { return &storage_; }
+       ~external_data()
+       {
+               if (!pext_.IsEmpty())
+               {
+                       static_cast<T*>(storage())->~T();
+                       pext_.Reset();
+               }
+       }
+       using data_storage = typename std::aligned_storage<sizeof(T)>::type;
+       data_storage storage_;
+       v8::UniquePersistent<v8::External> pext_;
+};
+
+template<typename T>
+typename std::enable_if<is_pointer_cast_allowed<T>::value, v8::Local<v8::Value>>::type
+set_external_data(v8::Isolate* isolate, T value)
+{
+       return v8::External::New(isolate, pointer_cast<T>(value));
+}
+
+template<typename T>
+typename std::enable_if<!is_pointer_cast_allowed<T>::value, v8::Local<v8::Value>>::type
+set_external_data(v8::Isolate* isolate, T&& value)
+{
+       return external_data<T>::set(isolate, std::forward<T>(value));
+}
+
+template<typename T>
+typename std::enable_if<is_pointer_cast_allowed<T>::value, T>::type
+get_external_data(v8::Handle<v8::Value> value)
+{
+       return pointer_cast<T>(value.As<v8::External>()->Value());
+}
+
+template<typename T>
+typename std::enable_if<!is_pointer_cast_allowed<T>::value, T&>::type
+get_external_data(v8::Handle<v8::Value> value)
+{
+       return external_data<T>::get(value.As<v8::External>());
+}
+
+template<typename F>
+typename std::enable_if<is_callable<F>::value,
+       typename function_traits<F>::return_type>::type
+invoke(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       return call_from_v8(std::forward<F>(get_external_data<F>(args.Data())), args);
+}
+
+template<typename F>
+typename std::enable_if<std::is_member_function_pointer<F>::value,
+       typename function_traits<F>::return_type>::type
+invoke(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       using arguments = typename function_traits<F>::arguments;
+       static_assert(std::tuple_size<arguments>::value > 0, "");
+       using class_type = typename std::tuple_element<0, arguments>::type;
+
+       return call_from_v8(from_v8<class_type&>(args.GetIsolate(), args.This()),
+               std::forward<F>(get_external_data<F>(args.Data())), args);
+}
+
+template<typename F>
+typename std::enable_if<is_void_return<F>::value>::type
+forward_ret(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       invoke<F>(args);
+}
+
+template<typename F>
+typename std::enable_if<!is_void_return<F>::value>::type
+forward_ret(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       args.GetReturnValue().Set(to_v8(args.GetIsolate(), invoke<F>(args)));
+}
+
+template<typename F>
+void forward_function(v8::FunctionCallbackInfo<v8::Value> const& args)
+{
+       static_assert(is_callable<F>::value || std::is_member_function_pointer<F>::value,
+               "required callable F");
+
+       v8::Isolate* isolate = args.GetIsolate();
+       v8::HandleScope scope(isolate);
+
+       try
+       {
+               forward_ret<F>(args);
+       }
+       catch (std::exception const& ex)
+       {
+               args.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+       }
+}
+
+} // namespace detail
+
+/// Wrap C++ function into new V8 function template
+template<typename F>
+v8::Handle<v8::FunctionTemplate> wrap_function_template(v8::Isolate* isolate, F&& func)
+{
+       using F_type = typename std::decay<F>::type;
+       return v8::FunctionTemplate::New(isolate, &detail::forward_function<F_type>,
+               detail::set_external_data(isolate, std::forward<F_type>(func)));
+}
+
+/// Wrap C++ function into new V8 function
+/// Set nullptr or empty string for name
+/// to make the function anonymous
+template<typename F>
+v8::Handle<v8::Function> wrap_function(v8::Isolate* isolate,
+       char const* name, F&& func)
+{
+       using F_type = typename std::decay<F>::type;
+       v8::Handle<v8::Function> fn = v8::Function::New(isolate,
+               &detail::forward_function<F_type>,
+               detail::set_external_data(isolate, std::forward<F_type>(func)));
+       if (name && *name)
+       {
+               fn->SetName(to_v8(isolate, name));
+       }
+       return fn;
+}
+
+} // namespace v8pp
+
+#endif // V8PP_FUNCTION_HPP_INCLUDED
diff --git a/v8pp/json.hpp b/v8pp/json.hpp
new file mode 100644
index 0000000..f435842
--- /dev/null
+++ b/v8pp/json.hpp
@@ -0,0 +1,70 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_JSON_HPP_INCLUDED
+#define V8PP_JSON_HPP_INCLUDED
+
+#include <string>
+#include <v8.h>
+
+namespace v8pp {
+
+/// Stringify V8 value to JSON
+/// return empty string for empty value
+inline std::string json_str(v8::Isolate* isolate, v8::Handle<v8::Value> value)
+{
+       if (value.IsEmpty())
+       {
+               return std::string();
+       }
+
+       v8::HandleScope scope(isolate);
+
+       v8::Local<v8::Object> json = isolate->GetCurrentContext()->
+               Global()->Get(v8::String::NewFromUtf8(isolate, "JSON"))->ToObject();
+       v8::Local<v8::Function> stringify = json->Get(
+               v8::String::NewFromUtf8(isolate, "stringify")).As<v8::Function>();
+
+       v8::Local<v8::Value> result = stringify->Call(json, 1, &value);
+       v8::String::Utf8Value const str(result);
+
+       return std::string(*str, str.length());
+}
+
+/// Parse JSON string into V8 value
+/// return empty value for empty string
+/// return Error value on parse error
+inline v8::Handle<v8::Value> json_parse(v8::Isolate* isolate, std::string const& str)
+{
+       if (str.empty())
+       {
+               return v8::Handle<v8::Value>();
+       }
+
+       v8::EscapableHandleScope scope(isolate);
+
+       v8::Local<v8::Object> json = isolate->GetCurrentContext()->
+               Global()->Get(v8::String::NewFromUtf8(isolate, "JSON"))->ToObject();
+       v8::Local<v8::Function> parse = json->Get(
+               v8::String::NewFromUtf8(isolate, "parse")).As<v8::Function>();
+
+       v8::Local<v8::Value> value = v8::String::NewFromUtf8(isolate, str.data(),
+               v8::String::kNormalString, static_cast<int>(str.size()));
+
+       v8::TryCatch try_catch;
+       v8::Local<v8::Value> result = parse->Call(json, 1, &value);
+       if (try_catch.HasCaught())
+       {
+               result = try_catch.Exception();
+       }
+       return scope.Escape(result);
+}
+
+} // namespace v8pp
+
+#endif // V8PP_JSON_HPP_INCLUDED
diff --git a/v8pp/module.hpp b/v8pp/module.hpp
new file mode 100644
index 0000000..52690da
--- /dev/null
+++ b/v8pp/module.hpp
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_MODULE_HPP_INCLUDED
+#define V8PP_MODULE_HPP_INCLUDED
+
+#include <v8.h>
+
+#include "v8pp/config.hpp"
+#include "v8pp/function.hpp"
+#include "v8pp/property.hpp"
+
+namespace v8pp {
+
+template<typename T>
+class class_;
+
+/// Module (similar to v8::ObjectTemplate)
+class module
+{
+public:
+       explicit module(v8::Isolate* isolate)
+               : isolate_(isolate)
+               , obj_(v8::ObjectTemplate::New(isolate))
+       {
+       }
+
+       explicit module(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> obj)
+               : isolate_(isolate)
+               , obj_(obj)
+       {
+       }
+
+       /// v8::Isolate where the module belongs
+       v8::Isolate* isolate() { return isolate_; }
+
+       /// Set a V8 value in the module with specified name
+       template<typename Data>
+       module& set(char const* name, v8::Handle<Data> value)
+       {
+               obj_->Set(v8pp::to_v8(isolate_, name), value);
+               return *this;
+       }
+
+       /// Set another module in the module with specified name
+       module& set(char const* name, module& m)
+       {
+               return set(name, m.obj_);
+       }
+
+       /// Set wrapped C++ class in the module with specified name
+       template<typename T>
+       module& set(char const* name, class_<T>& cl)
+       {
+               v8::HandleScope scope(isolate_);
+
+               cl.class_function_template()->SetClassName(v8pp::to_v8(isolate_, name));
+               return set(name, cl.js_function_template());
+       }
+
+       /// Set a C++ function in the module with specified name
+       template<typename Function, typename Fun = typename std::decay<Function>::type>
+       typename std::enable_if<detail::is_callable<Fun>::value, module&>::type
+       set(char const* name, Function&& func)
+       {
+               return set(name, wrap_function_template(isolate_, std::forward<Fun>(func)));
+       }
+
+       /// Set a C++ variable in the module with specified name
+       template<typename Variable>
+       typename std::enable_if<!detail::is_callable<Variable>::value, module&>::type
+       set(char const *name, Variable& var, bool readonly = false)
+       {
+               v8::HandleScope scope(isolate_);
+
+               v8::AccessorGetterCallback getter = &var_get<Variable>;
+               v8::AccessorSetterCallback setter = &var_set<Variable>;
+               if (readonly)
+               {
+                       setter = nullptr;
+               }
+
+               obj_->SetAccessor(v8pp::to_v8(isolate_, name), getter, setter,
+                       detail::set_external_data(isolate_, &var), v8::DEFAULT,
+                       v8::PropertyAttribute(v8::DontDelete | (setter ? 0 : v8::ReadOnly)));
+               return *this;
+       }
+
+       /// Set v8pp::property in the module with specified name
+       template<typename GetFunction, typename SetFunction>
+       module& set(char const *name, property_<GetFunction, SetFunction>&& prop)
+       {
+               using prop_type = property_<GetFunction, SetFunction>;
+
+               v8::HandleScope scope(isolate_);
+
+               v8::AccessorGetterCallback getter = prop_type::get;
+               v8::AccessorSetterCallback setter = prop_type::set;
+               if (prop_type::is_readonly)
+               {
+                       setter = nullptr;
+               }
+
+               obj_->SetAccessor(v8pp::to_v8(isolate_, name), getter, setter,
+                       detail::set_external_data(isolate_, std::forward<prop_type>(prop)),
+                       v8::DEFAULT,
+                       v8::PropertyAttribute(v8::DontDelete | (setter ? 0 : v8::ReadOnly)));
+               return *this;
+       }
+
+       /// Set another module as a read-only property
+       module& set_const(char const* name, module& m)
+       {
+               v8::HandleScope scope(isolate_);
+
+               obj_->Set(v8pp::to_v8(isolate_, name), m.obj_,
+                       v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+               return *this;
+       }
+
+       /// Set a value convertible to JavaScript as a read-only property
+       template<typename Value>
+       module& set_const(char const* name, Value const& value)
+       {
+               v8::HandleScope scope(isolate_);
+
+               obj_->Set(v8pp::to_v8(isolate_, name), to_v8(isolate_, value),
+                       v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+               return *this;
+       }
+
+       /// Create a new module instance in V8
+       v8::Local<v8::Object> new_instance() { return obj_->NewInstance(); }
+
+private:
+       template<typename Variable>
+       static void var_get(v8::Local<v8::String>,
+               v8::PropertyCallbackInfo<v8::Value> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               Variable* var = detail::get_external_data<Variable*>(info.Data());
+               info.GetReturnValue().Set(to_v8(isolate, *var));
+       }
+
+       template<typename Variable>
+       static void var_set(v8::Local<v8::String>, v8::Local<v8::Value> value,
+               v8::PropertyCallbackInfo<void> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               Variable* var = detail::get_external_data<Variable*>(info.Data());
+               *var = v8pp::from_v8<Variable>(isolate, value);
+       }
+
+       v8::Isolate* isolate_;
+       v8::Handle<v8::ObjectTemplate> obj_;
+};
+
+} // namespace v8pp
+
+#endif // V8PP_MODULE_HPP_INCLUDED
diff --git a/v8pp/object.hpp b/v8pp/object.hpp
new file mode 100644
index 0000000..7dcb501
--- /dev/null
+++ b/v8pp/object.hpp
@@ -0,0 +1,75 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_OBJECT_HPP_INCLUDED
+#define V8PP_OBJECT_HPP_INCLUDED
+
+#include <cstring>
+#include <v8.h>
+
+#include "v8pp/convert.hpp"
+
+namespace v8pp {
+
+/// Get optional value from V8 object by name.
+/// Dot symbols in option name delimits subobjects name.
+/// return false if the value doesn't exist in the options object
+template<typename T>
+bool get_option(v8::Isolate* isolate, v8::Handle<v8::Object> options,
+       char const* name, T& value)
+{
+       char const* dot = strchr(name, '.');
+       if (dot)
+       {
+               std::string const subname(name, dot);
+               v8::Local<v8::Object> suboptions;
+               return get_option(isolate, options, subname.c_str(), suboptions)
+                       && get_option(isolate, suboptions, dot + 1, value);
+       }
+       v8::Local<v8::Value> val = options->Get(v8pp::to_v8(isolate, name));
+       if (val.IsEmpty() || val->IsUndefined())
+       {
+               return false;
+       }
+       value = from_v8<T>(isolate, val);
+       return true;
+}
+
+/// Set named value in V8 object
+/// Dot symbols in option name delimits subobjects name.
+/// return false if the value doesn't exists in the options subobject
+template<typename T>
+bool set_option(v8::Isolate* isolate, v8::Handle<v8::Object> options,
+       char const* name, T const& value)
+{
+       char const* dot = strchr(name, '.');
+       if (dot)
+       {
+               std::string const subname(name, dot);
+               v8::HandleScope scope(isolate);
+               v8::Local<v8::Object> suboptions;
+               return get_option(isolate, options, subname.c_str(), suboptions)
+                       && set_option(isolate, suboptions, dot + 1, value);
+       }
+       options->Set(v8pp::to_v8(isolate, name), to_v8(isolate, value));
+       return true;
+}
+
+/// Set named constant in V8 object
+/// Subobject names are not supported
+template<typename T>
+void set_const(v8::Isolate* isolate, v8::Handle<v8::Object> options,
+       char const* name, T const& value)
+{
+       options->ForceSet(v8pp::to_v8(isolate, name), to_v8(isolate, value),
+               v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+}
+
+} // namespace v8pp
+
+#endif // V8PP_OBJECT_HPP_INCLUDED
diff --git a/v8pp/packages.config b/v8pp/packages.config
new file mode 100644
index 0000000..a9b883f
--- /dev/null
+++ b/v8pp/packages.config
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="v8.redist-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.redist-v120-x86" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.symbols-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8.symbols-v120-x86" version="5.4.500.8" targetFramework="native" />
+  <package id="v8-v120-x64" version="5.4.500.8" targetFramework="native" />
+  <package id="v8-v120-x86" version="5.4.500.8" targetFramework="native" />
+</packages>
\ No newline at end of file
diff --git a/v8pp/persistent.hpp b/v8pp/persistent.hpp
new file mode 100644
index 0000000..544ebac
--- /dev/null
+++ b/v8pp/persistent.hpp
@@ -0,0 +1,170 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_PERSISTENT_HPP_INCLUDED
+#define V8PP_PERSISTENT_HPP_INCLUDED
+
+#include <v8.h>
+
+#include "v8pp/convert.hpp"
+
+namespace v8pp {
+
+/// Moveable unique V8 persistent handle.
+/// Due to v8::UniquePersistent has no move constructor
+/// and assign operator defined, it cannot be stored in
+/// std::map, std::unordered_map.
+/// To resolve this issue add move support in dervied class.
+/// See https://groups.google.com/d/topic/v8-users/KV_LZqz41Ac/discussion
+template<typename T>
+struct persistent : public v8::UniquePersistent<T>
+{
+       using base_class = v8::UniquePersistent<T>;
+
+       persistent()
+               : base_class()
+       {
+       }
+
+       template<typename S>
+       persistent(v8::Isolate* isolate, v8::Handle<S> const& handle)
+               : base_class(isolate, handle)
+       {
+       }
+
+       template<typename S>
+       persistent(v8::Isolate* isolate, v8::PersistentBase<S> const& handle)
+               : base_class(isolate, handle)
+       {
+       }
+
+       persistent(persistent&& src)
+               : base_class(src.Pass())
+       {
+       }
+
+       persistent& operator=(persistent&& src)
+       {
+               if (&src != this)
+               {       
+                       base_class::operator=(src.Pass());
+               }
+               return *this;
+       }
+
+       persistent(persistent const&) = delete;
+       persistent& operator=(persistent const&) = delete;
+};
+
+/// Pointer to C++ object wrapped in V8 with v8::UniquePersistent handle
+template<typename T>
+class persistent_ptr
+{
+public:
+       /// Create an empty persistent pointer
+       persistent_ptr()
+               : value_()
+               , handle_()
+       {
+       }
+
+       /// Create a persistent pointer from a  pointer to a wrapped object,
+       /// store persistent handle to it
+       explicit persistent_ptr(v8::Isolate* isolate,  T* value)
+               : value_()
+       {
+               reset(isolate, value);
+       }
+
+       /// Create a persistent pointer from V8 Value, store persistent handle
+       explicit persistent_ptr(v8::Isolate* isolate, v8::Handle<v8::Value> handle)
+               : value_()
+       {
+               reset(isolate, from_v8<T*>(isolate, handle));
+       }
+
+       persistent_ptr(persistent_ptr&& src)
+               : value_(src.value_)
+               , handle_(std::move(src.handle_))
+       {
+               src.value_ = nullptr;
+       }
+
+
+       persistent_ptr& operator=(persistent_ptr&& src)
+       {
+               if (&src != this)
+               {
+                       value_ = src.value_;
+                       src.value_ = nullptr;
+                       handle_ = std::move(src.handle_);
+               }
+               return *this;
+       }
+
+       /// On destroy dispose persistent handle only
+       ~persistent_ptr() { reset(); }
+
+       /// Reset with a new pointer to wrapped C++ object, replace persistent handle
+       void reset(v8::Isolate* isolate, T* value)
+       {
+               if (value != value_)
+               {
+                       assert((value_ == nullptr) == handle_.IsEmpty());
+                       handle_.Reset();
+                       value_ = value;
+                       if (value_)
+                       {
+                               handle_.Reset(isolate, to_v8(isolate, value_));
+                       }
+               }
+       }
+
+       void reset() { reset(nullptr, nullptr); }
+
+       /// Get pointer to the wrapped C++ object
+       T* get() { return value_; }
+       T const* get() const { return value_; }
+
+       typedef T* (persistent_ptr<T>::*unspecfied_bool_type);
+
+       /// Safe bool cast
+       operator unspecfied_bool_type() const
+       {
+               return value_? &persistent_ptr<T>::value_ : nullptr;
+       }
+
+       /// Dereference pointer, valid if get() != nullptr
+       T& operator*() { assert(value_); return *value_; }
+       T const& operator*() const { assert(value_); return *value_; }
+
+       T* operator->() { assert(value_); return value_; }
+       T const* operator->() const { assert(value_); return value_; }
+
+       bool operator==(persistent_ptr const& rhs) const { return value_ == rhs.value_; }
+       bool operator!=(persistent_ptr const& rhs) const { return value_ != rhs.value_; }
+
+       void swap(persistent_ptr& rhs)
+       {
+               std::swap(value_, rhs.value_);
+               std::swap(handle_, rhs.handle_);
+       }
+
+       friend void swap(persistent_ptr& lhs, persistent_ptr& rhs)
+       {
+               lhs.swap(rhs);
+       }
+
+private:
+       T* value_;
+       v8::UniquePersistent<v8::Value> handle_;
+};
+
+} // namespace v8pp
+
+#endif // V8PP_PERSISTENT_HPP_INCLUDED
diff --git a/v8pp/property.hpp b/v8pp/property.hpp
new file mode 100644
index 0000000..dcc44e5
--- /dev/null
+++ b/v8pp/property.hpp
@@ -0,0 +1,400 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_PROPERTY_HPP_INCLUDED
+#define V8PP_PROPERTY_HPP_INCLUDED
+
+#include <cassert>
+
+#include "v8pp/convert.hpp"
+#include "v8pp/function.hpp"
+
+namespace v8pp {
+
+template<typename Get, typename Set>
+struct property_;
+
+namespace detail {
+
+struct getter_tag {};
+struct direct_getter_tag {};
+struct isolate_getter_tag {};
+
+struct setter_tag {};
+struct direct_setter_tag {};
+struct isolate_setter_tag {};
+
+template<typename F>
+using is_getter = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == 0 && !is_void_return<F>::value>;
+
+template<typename F>
+using is_direct_getter = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == 2 &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<0>,
+               v8::Local<v8::String>>::value &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<1>,
+               v8::PropertyCallbackInfo<v8::Value> const&>::value &&
+       is_void_return<F>::value
+>;
+
+template<typename F>
+using is_isolate_getter = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == 1 &&
+       is_first_arg_isolate<F>::value &&
+       !is_void_return<F>::value>;
+
+template<typename F>
+using is_setter = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == 1 && is_void_return<F>::value>;
+
+template<typename F>
+using is_direct_setter = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == 3 &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<0>,
+               v8::Local<v8::String>>::value &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<1>,
+               v8::Local<v8::Value>>::value &&
+       std::is_same<typename call_from_v8_traits<F>::template arg_type<2>,
+               v8::PropertyCallbackInfo<void> const&>::value &&
+       is_void_return<F>::value
+>;
+
+template<typename F>
+using is_isolate_setter = std::integral_constant<bool,
+       call_from_v8_traits<F>::arg_count == 2 &&
+       is_first_arg_isolate<F>::value &&
+       is_void_return<F>::value>;
+
+template<typename F>
+using select_getter_tag = typename std::conditional<is_direct_getter<F>::value,
+       direct_getter_tag,
+       typename std::conditional<is_isolate_getter<F>::value,
+               isolate_getter_tag, getter_tag>::type
+>::type;
+
+template<typename F>
+using select_setter_tag = typename std::conditional<is_direct_setter<F>::value,
+       direct_setter_tag,
+       typename std::conditional<is_isolate_setter<F>::value,
+               isolate_setter_tag, setter_tag>::type
+>::type;
+
+template<typename Get, typename Set, bool get_is_mem_fun>
+struct r_property_impl;
+
+template<typename Get, typename Set, bool set_is_mem_fun>
+struct rw_property_impl;
+
+template<typename Get, typename Set>
+struct r_property_impl<Get, Set, true>
+{
+       using Property = property_<Get, Set>;
+
+       using class_type = typename std::tuple_element<0,
+               typename function_traits<Get>::arguments> ::type;
+
+       static_assert(is_getter<Get>::value
+               || is_direct_getter<Get>::value
+               || is_isolate_getter<Get>::value,
+               "property get function must be either `T ()` or \
+               `void (v8::Local<v8::String> name, v8::PropertyCallbackInfo<v8::Value> const& info)` or \
+               `T (v8::Isolate*)`");
+
+       static void get_impl(class_type& obj, Get get, v8::Local<v8::String>,
+               v8::PropertyCallbackInfo<v8::Value> const& info, getter_tag)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               info.GetReturnValue().Set(to_v8(isolate, (obj.*get)()));
+       }
+
+       static void get_impl(class_type& obj, Get get,
+               v8::Local<v8::String> name, v8::PropertyCallbackInfo<v8::Value> const& info,
+               direct_getter_tag)
+       {
+               (obj.*get)(name, info);
+       }
+
+       static void get_impl(class_type& obj, Get get, v8::Local<v8::String>,
+               v8::PropertyCallbackInfo<v8::Value> const& info, isolate_getter_tag)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               info.GetReturnValue().Set(to_v8(isolate, (obj.*get)(isolate)));
+       }
+
+       static void get(v8::Local<v8::String> name,
+               v8::PropertyCallbackInfo<v8::Value> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+               try
+               {
+                       class_type& obj = v8pp::from_v8<class_type&>(isolate, info.This());
+                       Property const& prop = detail::get_external_data<Property>(info.Data());
+                       if (prop.get_)
+                       {
+                               get_impl(obj, prop.get_, name, info, select_getter_tag<Get>());
+                       }
+               }
+               catch (std::exception const& ex)
+               {
+                       info.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+               }
+       }
+
+       static void set(v8::Local<v8::String>, v8::Local<v8::Value>,
+               v8::PropertyCallbackInfo<void> const&)
+       {
+               assert(false && "never should be called");
+       }
+};
+
+template<typename Get, typename Set>
+struct r_property_impl<Get, Set, false>
+{
+       using Property = property_<Get, Set>;
+
+       static void get_impl(Get get, v8::Local<v8::String>,
+               v8::PropertyCallbackInfo<v8::Value> const& info, getter_tag)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               info.GetReturnValue().Set(to_v8(isolate, get()));
+       }
+
+       static void get_impl(Get get, v8::Local<v8::String> name,
+               v8::PropertyCallbackInfo<v8::Value> const& info, direct_getter_tag)
+       {
+               get(name, info);
+       }
+
+       static void get_impl(Get get, v8::Local<v8::String>,
+               v8::PropertyCallbackInfo<v8::Value> const& info, isolate_getter_tag)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               info.GetReturnValue().Set(to_v8(isolate, (get)(isolate)));
+       }
+
+       static void get(v8::Local<v8::String> name,
+               v8::PropertyCallbackInfo<v8::Value> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               Property const& prop = detail::get_external_data<Property>(info.Data());
+               assert(prop.get_);
+
+               if (prop.get_)
+               try
+               {
+                       get_impl(prop.get_, name, info, select_getter_tag<Get>());
+               }
+               catch (std::exception const& ex)
+               {
+                       info.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+               }
+       }
+
+       static void set(v8::Local<v8::String>, v8::Local<v8::Value>,
+               v8::PropertyCallbackInfo<void> const&)
+       {
+               assert(false && "never should be called");
+       }
+};
+
+template<typename Get, typename Set>
+struct rw_property_impl<Get, Set, true>
+       : r_property_impl<Get, Set, std::is_member_function_pointer<Get>::value>
+{
+       using Property = property_<Get, Set>;
+
+       using class_type = typename std::tuple_element<0,
+               typename function_traits<Set>::arguments>::type;
+
+       static void set_impl(class_type& obj, Set set, v8::Local<v8::String>,
+               v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> const& info,
+               setter_tag)
+       {
+               using value_type = typename call_from_v8_traits<Set>::template arg_type<0>;
+
+               v8::Isolate* isolate = info.GetIsolate();
+
+               (obj.*set)(v8pp::from_v8<value_type>(isolate, value));
+       }
+
+       static void set_impl(class_type& obj, Set set, v8::Local<v8::String> name,
+               v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> const& info,
+               direct_setter_tag)
+       {
+               (obj.*set)(name, value, info);
+       }
+
+       static void set_impl(class_type& obj, Set set, v8::Local<v8::String>, 
+               v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> const& info,
+               isolate_setter_tag)
+       {
+               using value_type = typename call_from_v8_traits<Set>::template arg_type<1>;
+
+               v8::Isolate* isolate = info.GetIsolate();
+               (obj.*set)(isolate, v8pp::from_v8<value_type>(isolate, value));
+       }
+
+       static void set(v8::Local<v8::String> name, v8::Local<v8::Value> value,
+               v8::PropertyCallbackInfo<void> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+               try
+               {
+                       class_type& obj = v8pp::from_v8<class_type&>(isolate, info.This());
+                       Property const& prop = detail::get_external_data<Property>(info.Data());
+                       assert(prop.set_);
+                       if (prop.set_)
+                       {
+                               set_impl(obj, prop.set_, name, value, info, select_setter_tag<Set>());
+                       }
+               }
+               catch (std::exception const& ex)
+               {
+                       info.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+               }
+       }
+};
+
+template<typename Get, typename Set>
+struct rw_property_impl<Get, Set, false>
+       : r_property_impl<Get, Set, std::is_member_function_pointer<Get>::value>
+{
+       using Property = property_<Get, Set>;
+
+       static void set_impl(Set set, v8::Local<v8::String>,
+               v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> const& info,
+               setter_tag)
+       {
+               using value_type = typename call_from_v8_traits<Set>::template arg_type<0>;
+
+               v8::Isolate* isolate = info.GetIsolate();
+
+               set(v8pp::from_v8<value_type>(isolate, value));
+       }
+
+       static void set_impl(Set set, v8::Local<v8::String> name,
+               v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> const& info,
+               direct_setter_tag)
+       {
+               set(name, value, info);
+       }
+
+       static void set_impl(Set set, v8::Local<v8::String>,
+               v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> const& info,
+               isolate_setter_tag)
+       {
+               using value_type = typename call_from_v8_traits<Set>::template arg_type<1>;
+
+               v8::Isolate* isolate = info.GetIsolate();
+
+               set(isolate, v8pp::from_v8<value_type>(isolate, value));
+       }
+
+       static void set(v8::Local<v8::String> name, v8::Local<v8::Value> value,
+               v8::PropertyCallbackInfo<void> const& info)
+       {
+               v8::Isolate* isolate = info.GetIsolate();
+
+               Property const& prop = detail::get_external_data<Property>(info.Data());
+               assert(prop.set_);
+
+               if (prop.set_)
+               try
+               {
+                       set_impl(prop.set_, name, value, info, select_setter_tag<Set>());
+               }
+               catch (std::exception const& ex)
+               {
+                       info.GetReturnValue().Set(throw_ex(isolate, ex.what()));
+               }
+       }
+};
+
+} // namespace detail
+
+/// Property with get and set functions
+template<typename Get, typename Set>
+struct property_
+       : detail::rw_property_impl<Get, Set, std::is_member_function_pointer<Set>::value>
+{
+       static_assert(detail::is_getter<Get>::value
+               || detail::is_direct_getter<Get>::value
+               || detail::is_isolate_getter<Get>::value,
+               "property get function must be either `T ()` or "
+               "`void (v8::Local<v8::String> name, v8::PropertyCallbackInfo<v8::Value> const& info)` or "
+               "`T (v8::Isolate*)`");
+
+       static_assert(detail::is_setter<Set>::value
+               || detail::is_direct_setter<Set>::value
+               || detail::is_isolate_setter<Set>::value,
+               "property set function must be either `void (T)` or \
+               `void (v8::Local<v8::String> name, v8::Local<v8::Value> value, v8::PropertyCallbackInfo<void> 
const& info)` or \
+               `void (v8::Isolate*, T)`");
+
+       Get get_;
+       Set set_;
+
+       enum { is_readonly = false };
+};
+
+/// Read-only property class specialization for get only method
+template<typename Get>
+struct property_<Get, Get>
+       : detail::r_property_impl<Get, Get, std::is_member_function_pointer<Get>::value>
+{
+       static_assert(detail::is_getter<Get>::value
+               || detail::is_direct_getter<Get>::value
+               || detail::is_isolate_getter<Get>::value,
+               "property get function must be either `T ()` or "
+               "void (v8::Local<v8::String> name, v8::PropertyCallbackInfo<v8::Value> const& info)` or "
+               "`T (v8::Isolate*)`");
+
+       Get get_;
+
+       enum { is_readonly = true };
+};
+
+/// Create read/write property from get and set member functions
+template<typename Get, typename Set>
+property_<Get, Set> property(Get get, Set set)
+{
+       property_<Get, Set> prop;
+       prop.get_ = get;
+       prop.set_ = set;
+       return prop;
+}
+
+/// Create read/write property from get and set member functions, match getter via const this
+template<class Class, typename Ret, typename Arg>
+property_<Ret (Class::*) () const, void (Class::*) (Arg)>
+property(Ret (Class::*get) () const, void (Class::*set) (Arg))
+{
+       property_<Ret (Class::*) () const, void (Class::*) (Arg)> prop;
+       prop.get_ = get;
+       prop.set_ = set;
+       return prop;
+}
+
+/// Create read-only property from a get function
+template<typename Get>
+property_<Get, Get> property(Get get)
+{
+       property_<Get, Get> prop;
+       prop.get_ = get;
+       return prop;
+}
+
+} // namespace v8pp
+
+#endif // V8PP_PROPERTY_HPP_INCLUDED
diff --git a/v8pp/throw_ex.hpp b/v8pp/throw_ex.hpp
new file mode 100644
index 0000000..8182774
--- /dev/null
+++ b/v8pp/throw_ex.hpp
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_THROW_EX_HPP_INCLUDED
+#define V8PP_THROW_EX_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+
+#include <v8.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+namespace v8pp {
+
+inline v8::Handle<v8::Value> throw_ex(v8::Isolate* isolate, char const* str,
+       v8::Local<v8::Value> (*exception_ctor)(v8::Handle<v8::String>) = v8::Exception::Error)
+{
+       v8::EscapableHandleScope scope(isolate);
+
+       v8::Handle<v8::String> message;
+#ifdef _WIN32
+       int const len = ::MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+       if (len > 0)
+       {
+               std::vector<wchar_t> buf(len);
+               ::MultiByteToWideChar(CP_ACP, 0, str, -1, &buf[0], len);
+               uint16_t const* data = reinterpret_cast<uint16_t const*>(&buf[0]);
+               message = v8::String::NewFromTwoByte(isolate, data,
+                       v8::String::kNormalString, len - 1);
+       }
+#else
+       message = v8::String::NewFromUtf8(isolate, str);
+#endif
+       return scope.Escape(isolate->ThrowException(exception_ctor(message)));
+}
+
+inline v8::Handle<v8::Value> throw_ex(v8::Isolate* isolate, std::string const& str,
+       v8::Local<v8::Value> (*exception_ctor)(v8::Handle<v8::String>) = v8::Exception::Error)
+{
+       return throw_ex(isolate, str.c_str(), exception_ctor);
+}
+
+} // namespace v8pp
+
+#endif // V8PP_THROW_EX_HPP_INCLUDED
diff --git a/v8pp/utility.hpp b/v8pp/utility.hpp
new file mode 100644
index 0000000..8e2df37
--- /dev/null
+++ b/v8pp/utility.hpp
@@ -0,0 +1,294 @@
+//
+// Copyright (c) 2013-2016 Pavel Medvedev. All rights reserved.
+//
+// This file is part of v8pp (https://github.com/pmed/v8pp) project.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef V8PP_UTILITY_HPP_INCLUDED
+#define V8PP_UTILITY_HPP_INCLUDED
+
+#include <tuple>
+#include <type_traits>
+
+namespace v8pp { namespace detail {
+
+template<typename T>
+struct tuple_tail;
+
+template<typename Head, typename... Tail>
+struct tuple_tail<std::tuple<Head, Tail...>>
+{
+       using type = std::tuple<Tail...>;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function traits
+//
+template<typename F>
+struct function_traits;
+
+template<typename R, typename ...Args>
+struct function_traits<R (Args...)>
+{
+       using return_type = R;
+       using arguments = std::tuple<Args...>;
+};
+
+// function pointer
+template<typename R, typename ...Args>
+struct function_traits<R (*)(Args...)>
+       : function_traits<R (Args...)>
+{
+       using pointer_type = R (*)(Args...);
+};
+
+// member function pointer
+template<typename C, typename R, typename ...Args>
+struct function_traits<R (C::*)(Args...)>
+       : function_traits<R (C&, Args...)>
+{
+       template<typename D = C>
+       using pointer_type = R (D::*)(Args...);
+};
+
+// const member function pointer
+template<typename C, typename R, typename ...Args>
+struct function_traits<R (C::*)(Args...) const>
+       : function_traits<R (C const&, Args...)>
+{
+       template<typename D = C>
+       using pointer_type = R (D::*)(Args...) const;
+};
+
+// volatile member function pointer
+template<typename C, typename R, typename ...Args>
+struct function_traits<R (C::*)(Args...) volatile>
+       : function_traits<R (C volatile&, Args...)>
+{
+       template<typename D = C>
+       using pointer_type = R (D::*)(Args...) volatile;
+};
+
+// const volatile member function pointer
+template<typename C, typename R, typename ...Args>
+struct function_traits<R (C::*)(Args...) const volatile>
+       : function_traits<R (C const volatile&, Args...)>
+{
+       template<typename D = C>
+       using pointer_type = R (D::*)(Args...) const volatile;
+};
+
+// member object pointer
+template<typename C, typename R>
+struct function_traits<R (C::*)>
+       : function_traits<R (C&)>
+{
+       template<typename D = C>
+       using pointer_type = R (D::*);
+};
+
+// const member object pointer
+template<typename C, typename R>
+struct function_traits<const R (C::*)>
+       : function_traits<R (C const&)>
+{
+       template<typename D = C>
+       using pointer_type = const R (D::*);
+};
+
+// volatile member object pointer
+template<typename C, typename R>
+struct function_traits<volatile R (C::*)>
+       : function_traits<R (C volatile&)>
+{
+       template<typename D = C>
+       using pointer_type = volatile R (D::*);
+};
+
+// const volatile member object pointer
+template<typename C, typename R>
+struct function_traits<const volatile R (C::*)>
+       : function_traits<R (C const volatile&)>
+{
+       template<typename D = C>
+       using pointer_type = const volatile R (D::*);
+};
+
+// function object, std::function, lambda
+template<typename F>
+struct function_traits
+{
+       static_assert(!std::is_bind_expression<F>::value,
+               "std::bind result is not supported yet");
+private:
+       using callable_traits = function_traits<decltype(&F::operator())>;
+public:
+       using return_type = typename callable_traits::return_type;
+       using arguments = typename tuple_tail<typename callable_traits::arguments>::type;
+};
+
+template<typename F>
+struct function_traits<F&> : function_traits<F> {};
+
+template<typename F>
+struct function_traits<F&&> : function_traits<F> {};
+
+template<typename F>
+using is_void_return = std::is_same<void,
+       typename function_traits<F>::return_type>;
+
+template<typename F, bool is_class>
+struct is_callable_impl
+       : std::is_function<typename std::remove_pointer<F>::type>
+{
+};
+
+template<typename F>
+struct is_callable_impl<F, true>
+{
+private:
+       struct fallback { void operator()(); };
+       struct derived : F, fallback {};
+
+       template<typename U, U> struct check;
+
+       template<typename>
+       static std::true_type test(...);
+
+       template<typename C>
+       static std::false_type test(check<void(fallback::*)(), &C::operator()>*);
+
+       using type = decltype(test<derived>(0));
+public:
+       static const bool value = type::value;
+};
+
+template<typename F>
+using is_callable = std::integral_constant<bool,
+       is_callable_impl<F, std::is_class<F>::value>::value>;
+
+#if (__cplusplus > 201402L) || (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918)
+using std::index_sequence;
+using std::make_index_sequence;
+#else
+/////////////////////////////////////////////////////////////////////////////
+//
+// integer_sequence
+//
+template<typename T, T... I>
+struct integer_sequence
+{
+       using type = T;
+       static size_t size() { return sizeof...(I); }
+
+       template<T N>
+       using append = integer_sequence<T, I..., N>;
+
+       using next = append<sizeof...(I)>;
+};
+
+template<typename T, T Index, size_t N>
+struct sequence_generator
+{
+       using type = typename sequence_generator<T, Index - 1, N - 1>::type::next;
+};
+
+template<typename T, T Index>
+struct sequence_generator<T, Index, 0ul>
+{
+       using type = integer_sequence<T>;
+};
+
+template<size_t... I>
+using index_sequence = integer_sequence<size_t, I...>;
+
+template<typename T, T N>
+using make_integer_sequence = typename sequence_generator<T, N, N>::type;
+
+template<size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// apply_tuple
+//
+template<typename F, typename Tuple, size_t... Indices>
+typename function_traits<F>::return_type apply_impl(
+       F&& f, Tuple&& t, index_sequence<Indices...>)
+{
+       return std::forward<F>(f)(std::get<Indices>(std::forward<Tuple>(t))...);
+}
+
+template<typename F, typename Tuple>
+typename function_traits<F>::return_type apply_tuple(F&& f, Tuple&& t)
+{
+       using Indices = make_index_sequence<
+               std::tuple_size<typename std::decay<Tuple>::type>::value>;
+       return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
+}
+
+template<typename F, typename ...Args>
+typename function_traits<F>::return_type apply(F&& f, Args&&... args)
+{
+       return std::forward<F>(f)(std::forward<Args>(args)...);
+}
+
+/// Type information for custom RTTI
+class type_info
+{
+public:
+       std::string const& name() const { return name_; }
+       bool operator==(type_info const& other) const { return name_ == other.name_; }
+       bool operator!=(type_info const& other) const { return name_ != other.name_; }
+private:
+       template<typename T> friend type_info type_id();
+       type_info(char const* name, size_t size)
+               : name_(name, size)
+       {
+       }
+       std::string name_;
+};
+
+/// Get type information for type T
+/// Idea  borrowed from https://github.com/Manu343726/ctti
+template<typename T>
+type_info type_id()
+{
+#if defined(_MSC_VER)
+       #define V8PP_PRETTY_FUNCTION __FUNCSIG__
+       #define V8PP_PRETTY_FUNCTION_PREFIX "class v8pp::detail::type_info __cdecl v8pp::detail::type_id<"
+       #define V8PP_PRETTY_FUNCTION_SUFFIX ">(void)"
+#elif defined(__clang__) || defined(__GNUC__)
+       #define V8PP_PRETTY_FUNCTION __PRETTY_FUNCTION__
+       #if !defined(__clang__)
+               #define V8PP_PRETTY_FUNCTION_PREFIX "v8pp::detail::type_info v8pp::detail::type_id() [with T 
= "
+       #else
+               #define V8PP_PRETTY_FUNCTION_PREFIX "v8pp::detail::type_info v8pp::detail::type_id() [T = "
+       #endif
+       #define V8PP_PRETTY_FUNCTION_SUFFIX "]"
+#else
+       #error "Unknown compiler"
+#endif
+
+#define V8PP_PRETTY_FUNCTION_LEN (sizeof(V8PP_PRETTY_FUNCTION) - 1)
+#define V8PP_PRETTY_FUNCTION_PREFIX_LEN (sizeof(V8PP_PRETTY_FUNCTION_PREFIX) - 1)
+#define V8PP_PRETTY_FUNCTION_SUFFIX_LEN (sizeof(V8PP_PRETTY_FUNCTION_SUFFIX) - 1)
+
+       return type_info(V8PP_PRETTY_FUNCTION + V8PP_PRETTY_FUNCTION_PREFIX_LEN,
+               V8PP_PRETTY_FUNCTION_LEN - V8PP_PRETTY_FUNCTION_PREFIX_LEN - V8PP_PRETTY_FUNCTION_SUFFIX_LEN);
+
+#undef V8PP_PRETTY_FUNCTION
+#undef V8PP_PRETTY_FUNCTION_PREFIX
+#undef V8PP_PRETTY_FUNCTION_SUFFFIX
+#undef V8PP_PRETTY_FUNCTION_LEN
+#undef V8PP_PRETTY_FUNCTION_PREFIX_LEN
+#undef V8PP_PRETTY_FUNCTION_SUFFFIX_LEN
+}
+
+}} // namespace v8pp::detail
+
+#endif // V8PP_UTILITY_HPP_INCLUDED
diff --git a/v8pp/v8pp.vcxproj b/v8pp/v8pp.vcxproj
new file mode 100644
index 0000000..e7fc9c6
--- /dev/null
+++ b/v8pp/v8pp.vcxproj
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props" 
Condition="Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props" 
Condition="Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" />
+  <Import Project="..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props" 
Condition="Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" />
+  <Import Project="..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props" 
Condition="Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" />
+  <Import Project="..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props" 
Condition="Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" />
+  <Import Project="..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props" 
Condition="Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="context.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="call_from_v8.hpp" />
+    <ClInclude Include="call_v8.hpp" />
+    <ClInclude Include="class.hpp" />
+    <ClInclude Include="config.hpp" />
+    <ClInclude Include="context.hpp" />
+    <ClInclude Include="convert.hpp" />
+    <ClInclude Include="factory.hpp" />
+    <ClInclude Include="function.hpp" />
+    <ClInclude Include="json.hpp" />
+    <ClInclude Include="module.hpp" />
+    <ClInclude Include="object.hpp" />
+    <ClInclude Include="persistent.hpp" />
+    <ClInclude Include="property.hpp" />
+    <ClInclude Include="throw_ex.hpp" />
+    <ClInclude Include="utility.hpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{2E6CFC3D-5A08-4909-8D1A-3469063D169B}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>v8pp</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" 
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="../common.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup />
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib />
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib />
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Lib />
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Lib />
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet 
Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. 
The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x86.5.4.500.8\build\native\v8.redist-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x86.5.4.500.8\build\native\v8.symbols-v120-x86.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x86.5.4.500.8\build\native\v8-v120-x86.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.redist-v120-x64.5.4.500.8\build\native\v8.redist-v120-x64.props'))" />
+    <Error 
Condition="!Exists('..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8.symbols-v120-x64.5.4.500.8\build\native\v8.symbols-v120-x64.props'))" />
+    <Error Condition="!Exists('..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props')" 
Text="$([System.String]::Format('$(ErrorText)', 
'..\packages\v8-v120-x64.5.4.500.8\build\native\v8-v120-x64.props'))" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/v8pp/v8pp.vcxproj.filters b/v8pp/v8pp.vcxproj.filters
new file mode 100644
index 0000000..201d54d
--- /dev/null
+++ b/v8pp/v8pp.vcxproj.filters
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <ItemGroup>
+    <ClCompile Include="context.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="context.hpp" />
+    <ClInclude Include="config.hpp" />
+    <ClInclude Include="module.hpp" />
+    <ClInclude Include="throw_ex.hpp" />
+    <ClInclude Include="class.hpp" />
+    <ClInclude Include="factory.hpp" />
+    <ClInclude Include="call_from_v8.hpp" />
+    <ClInclude Include="call_v8.hpp" />
+    <ClInclude Include="utility.hpp" />
+    <ClInclude Include="convert.hpp" />
+    <ClInclude Include="property.hpp" />
+    <ClInclude Include="function.hpp" />
+    <ClInclude Include="object.hpp" />
+    <ClInclude Include="json.hpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+</Project>
\ No newline at end of file



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]