Add valijson.
Currently it seg faults due to stack overflow when validating with `glTF.schema.json`
diff --git a/examples/validator/CMakeLists.txt b/examples/validator/CMakeLists.txt
new file mode 100644
index 0000000..1e98b07
--- /dev/null
+++ b/examples/validator/CMakeLists.txt
@@ -0,0 +1,53 @@
+project(tinygltf-validator CXX)
+
+cmake_minimum_required(VERSION 3.2)
+
+# Use C++11
+set(CMAKE_CXX_STANDARD 11)
+
+# exe
+add_executable(tinygltf-validator
+    tinygltf-validate.cc
+    json11.cpp)
+
+target_include_directories(tinygltf-validator
+    PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/valijson/include
+        ${CMAKE_CURRENT_SOURCE_DIR}/
+    )
+
+# Enable more compiler warnings, except when using Visual Studio compiler
+if(NOT MSVC)
+    target_compile_options(tinygltf-validator
+        PUBLIC
+            -Wall -Wextra)
+endif()
+target_compile_definitions(tinygltf-validator
+    PRIVATE
+        -DJSON_SCHEMA_VALIDATOR_EXPORTS)
+
+# regex with boost if gcc < 4.8 - default is std::regex
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0")
+        find_package(Boost COMPONENTS regex)
+        if(NOT Boost_FOUND)
+            message(STATUS "GCC less then 4.9 and boost-regex NOT found - no regex used")
+            target_compile_definitions(tinygltf-validator PRIVATE -DJSON_SCHEMA_NO_REGEX)
+        else()
+            message(STATUS "GCC less then 4.9 and boost-regex FOUND - using boost::regex")
+            target_compile_definitions(tinygltf-validator PRIVATE -DJSON_SCHEMA_BOOST_REGEX)
+            target_include_directories(tinygltf-validator PRIVATE ${Boost_INCLUDE_DIRS})
+            target_link_libraries(tinygltf-validator PRIVATE ${Boost_LIBRARIES})
+        endif()
+    endif()
+endif()
+
+# test-zone
+# enable_testing()
+
+install ( TARGETS
+  tinygltf-validator
+  DESTINATION
+  bin
+  )
+
diff --git a/examples/validator/LICENSE.json11.txt b/examples/validator/LICENSE.json11.txt
new file mode 100755
index 0000000..691742e
--- /dev/null
+++ b/examples/validator/LICENSE.json11.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Dropbox, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF 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/examples/validator/Makefile b/examples/validator/Makefile
new file mode 100644
index 0000000..6b3abde
--- /dev/null
+++ b/examples/validator/Makefile
@@ -0,0 +1,4 @@
+EXTRA_CXXFLAGS=-fsanitize=address
+
+all:
+	clang++ $(EXTRA_CXXFLAGS) -g -O1 -I. -Ivalijson/include tinygltf-validate.cc json11.cpp -o tinygltf-validate
diff --git a/examples/validator/README.md b/examples/validator/README.md
new file mode 100644
index 0000000..2bca145
--- /dev/null
+++ b/examples/validator/README.md
@@ -0,0 +1,15 @@
+Currently it causes stack-overflow in runtime.
+
+```
+$ ./tinygltf-validate schema_dir ../../models/Cube/Cube.gltf
+
+...
+
+==17033==ERROR: AddressSanitizer: stack-overflow on address 0x7fff55415d68 (pc 0x0000004c62de bp 0x7fff554165c0 sp 0x7fff55415d70 T0)
+    #0 0x4c62dd in __asan_memset /tmp/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cc:27:3
+    #1 0x53a7a7 in std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_Vector_impl::_Vector_impl(std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&) /usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:91:37
+    #2 0x53a6f1 in std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_Vector_base(unsigned long, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&) /usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:135:9
+    #3 0x53a9e2 in std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::vector(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) /usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:319:9
+    #4 0x584313 in valijson::ValidationVisitor<valijson::adapters::Json11Adapter>::ValidationVisitor(valijson::ValidationVisitor<valijson::adapters::Json11Adapter> const&) /home/syoyo/work/tinygltf/examples/validator/valijson/include/valijson/validation_visitor.hpp:26:7
+```
+
diff --git a/examples/validator/json11.cpp b/examples/validator/json11.cpp
new file mode 100644
index 0000000..9647846
--- /dev/null
+++ b/examples/validator/json11.cpp
@@ -0,0 +1,788 @@
+/* Copyright (c) 2013 Dropbox, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "json11.hpp"
+#include <cassert>
+#include <cmath>
+#include <cstdlib>
+#include <cstdio>
+#include <limits>
+
+namespace json11 {
+
+static const int max_depth = 200;
+
+using std::string;
+using std::vector;
+using std::map;
+using std::make_shared;
+using std::initializer_list;
+using std::move;
+
+/* Helper for representing null - just a do-nothing struct, plus comparison
+ * operators so the helpers in JsonValue work. We can't use nullptr_t because
+ * it may not be orderable.
+ */
+struct NullStruct {
+    bool operator==(NullStruct) const { return true; }
+    bool operator<(NullStruct) const { return false; }
+};
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Serialization
+ */
+
+static void dump(NullStruct, string &out) {
+    out += "null";
+}
+
+static void dump(double value, string &out) {
+    if (std::isfinite(value)) {
+        char buf[32];
+        snprintf(buf, sizeof buf, "%.17g", value);
+        out += buf;
+    } else {
+        out += "null";
+    }
+}
+
+static void dump(int value, string &out) {
+    char buf[32];
+    snprintf(buf, sizeof buf, "%d", value);
+    out += buf;
+}
+
+static void dump(bool value, string &out) {
+    out += value ? "true" : "false";
+}
+
+static void dump(const string &value, string &out) {
+    out += '"';
+    for (size_t i = 0; i < value.length(); i++) {
+        const char ch = value[i];
+        if (ch == '\\') {
+            out += "\\\\";
+        } else if (ch == '"') {
+            out += "\\\"";
+        } else if (ch == '\b') {
+            out += "\\b";
+        } else if (ch == '\f') {
+            out += "\\f";
+        } else if (ch == '\n') {
+            out += "\\n";
+        } else if (ch == '\r') {
+            out += "\\r";
+        } else if (ch == '\t') {
+            out += "\\t";
+        } else if (static_cast<uint8_t>(ch) <= 0x1f) {
+            char buf[8];
+            snprintf(buf, sizeof buf, "\\u%04x", ch);
+            out += buf;
+        } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
+                   && static_cast<uint8_t>(value[i+2]) == 0xa8) {
+            out += "\\u2028";
+            i += 2;
+        } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
+                   && static_cast<uint8_t>(value[i+2]) == 0xa9) {
+            out += "\\u2029";
+            i += 2;
+        } else {
+            out += ch;
+        }
+    }
+    out += '"';
+}
+
+static void dump(const Json::array &values, string &out) {
+    bool first = true;
+    out += "[";
+    for (const auto &value : values) {
+        if (!first)
+            out += ", ";
+        value.dump(out);
+        first = false;
+    }
+    out += "]";
+}
+
+static void dump(const Json::object &values, string &out) {
+    bool first = true;
+    out += "{";
+    for (const auto &kv : values) {
+        if (!first)
+            out += ", ";
+        dump(kv.first, out);
+        out += ": ";
+        kv.second.dump(out);
+        first = false;
+    }
+    out += "}";
+}
+
+void Json::dump(string &out) const {
+    m_ptr->dump(out);
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Value wrappers
+ */
+
+template <Json::Type tag, typename T>
+class Value : public JsonValue {
+protected:
+
+    // Constructors
+    explicit Value(const T &value) : m_value(value) {}
+    explicit Value(T &&value)      : m_value(move(value)) {}
+
+    // Get type tag
+    Json::Type type() const override {
+        return tag;
+    }
+
+    // Comparisons
+    bool equals(const JsonValue * other) const override {
+        return m_value == static_cast<const Value<tag, T> *>(other)->m_value;
+    }
+    bool less(const JsonValue * other) const override {
+        return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
+    }
+
+    const T m_value;
+    void dump(string &out) const override { json11::dump(m_value, out); }
+};
+
+class JsonDouble final : public Value<Json::NUMBER, double> {
+    double number_value() const override { return m_value; }
+    int int_value() const override { return static_cast<int>(m_value); }
+    bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
+    bool less(const JsonValue * other)   const override { return m_value <  other->number_value(); }
+public:
+    explicit JsonDouble(double value) : Value(value) {}
+};
+
+class JsonInt final : public Value<Json::NUMBER, int> {
+    double number_value() const override { return m_value; }
+    int int_value() const override { return m_value; }
+    bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
+    bool less(const JsonValue * other)   const override { return m_value <  other->number_value(); }
+public:
+    explicit JsonInt(int value) : Value(value) {}
+};
+
+class JsonBoolean final : public Value<Json::BOOL, bool> {
+    bool bool_value() const override { return m_value; }
+public:
+    explicit JsonBoolean(bool value) : Value(value) {}
+};
+
+class JsonString final : public Value<Json::STRING, string> {
+    const string &string_value() const override { return m_value; }
+public:
+    explicit JsonString(const string &value) : Value(value) {}
+    explicit JsonString(string &&value)      : Value(move(value)) {}
+};
+
+class JsonArray final : public Value<Json::ARRAY, Json::array> {
+    const Json::array &array_items() const override { return m_value; }
+    const Json & operator[](size_t i) const override;
+public:
+    explicit JsonArray(const Json::array &value) : Value(value) {}
+    explicit JsonArray(Json::array &&value)      : Value(move(value)) {}
+};
+
+class JsonObject final : public Value<Json::OBJECT, Json::object> {
+    const Json::object &object_items() const override { return m_value; }
+    const Json & operator[](const string &key) const override;
+public:
+    explicit JsonObject(const Json::object &value) : Value(value) {}
+    explicit JsonObject(Json::object &&value)      : Value(move(value)) {}
+};
+
+class JsonNull final : public Value<Json::NUL, NullStruct> {
+public:
+    JsonNull() : Value({}) {}
+};
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Static globals - static-init-safe
+ */
+struct Statics {
+    const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();
+    const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true);
+    const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
+    const string empty_string;
+    const vector<Json> empty_vector;
+    const map<string, Json> empty_map;
+    Statics() {}
+};
+
+static const Statics & statics() {
+    static const Statics s {};
+    return s;
+}
+
+static const Json & static_null() {
+    // This has to be separate, not in Statics, because Json() accesses statics().null.
+    static const Json json_null;
+    return json_null;
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Constructors
+ */
+
+Json::Json() noexcept                  : m_ptr(statics().null) {}
+Json::Json(std::nullptr_t) noexcept    : m_ptr(statics().null) {}
+Json::Json(double value)               : m_ptr(make_shared<JsonDouble>(value)) {}
+Json::Json(int value)                  : m_ptr(make_shared<JsonInt>(value)) {}
+Json::Json(bool value)                 : m_ptr(value ? statics().t : statics().f) {}
+Json::Json(const string &value)        : m_ptr(make_shared<JsonString>(value)) {}
+Json::Json(string &&value)             : m_ptr(make_shared<JsonString>(move(value))) {}
+Json::Json(const char * value)         : m_ptr(make_shared<JsonString>(value)) {}
+Json::Json(const Json::array &values)  : m_ptr(make_shared<JsonArray>(values)) {}
+Json::Json(Json::array &&values)       : m_ptr(make_shared<JsonArray>(move(values))) {}
+Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
+Json::Json(Json::object &&values)      : m_ptr(make_shared<JsonObject>(move(values))) {}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Accessors
+ */
+
+Json::Type Json::type()                           const { return m_ptr->type();         }
+double Json::number_value()                       const { return m_ptr->number_value(); }
+int Json::int_value()                             const { return m_ptr->int_value();    }
+bool Json::bool_value()                           const { return m_ptr->bool_value();   }
+const string & Json::string_value()               const { return m_ptr->string_value(); }
+const vector<Json> & Json::array_items()          const { return m_ptr->array_items();  }
+const map<string, Json> & Json::object_items()    const { return m_ptr->object_items(); }
+const Json & Json::operator[] (size_t i)          const { return (*m_ptr)[i];           }
+const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key];         }
+
+double                    JsonValue::number_value()              const { return 0; }
+int                       JsonValue::int_value()                 const { return 0; }
+bool                      JsonValue::bool_value()                const { return false; }
+const string &            JsonValue::string_value()              const { return statics().empty_string; }
+const vector<Json> &      JsonValue::array_items()               const { return statics().empty_vector; }
+const map<string, Json> & JsonValue::object_items()              const { return statics().empty_map; }
+const Json &              JsonValue::operator[] (size_t)         const { return static_null(); }
+const Json &              JsonValue::operator[] (const string &) const { return static_null(); }
+
+const Json & JsonObject::operator[] (const string &key) const {
+    auto iter = m_value.find(key);
+    return (iter == m_value.end()) ? static_null() : iter->second;
+}
+const Json & JsonArray::operator[] (size_t i) const {
+    if (i >= m_value.size()) return static_null();
+    else return m_value[i];
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Comparison
+ */
+
+bool Json::operator== (const Json &other) const {
+    if (m_ptr == other.m_ptr)
+        return true;
+    if (m_ptr->type() != other.m_ptr->type())
+        return false;
+
+    return m_ptr->equals(other.m_ptr.get());
+}
+
+bool Json::operator< (const Json &other) const {
+    if (m_ptr == other.m_ptr)
+        return false;
+    if (m_ptr->type() != other.m_ptr->type())
+        return m_ptr->type() < other.m_ptr->type();
+
+    return m_ptr->less(other.m_ptr.get());
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Parsing
+ */
+
+/* esc(c)
+ *
+ * Format char c suitable for printing in an error message.
+ */
+static inline string esc(char c) {
+    char buf[12];
+    if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
+        snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
+    } else {
+        snprintf(buf, sizeof buf, "(%d)", c);
+    }
+    return string(buf);
+}
+
+static inline bool in_range(long x, long lower, long upper) {
+    return (x >= lower && x <= upper);
+}
+
+namespace {
+/* JsonParser
+ *
+ * Object that tracks all state of an in-progress parse.
+ */
+struct JsonParser final {
+
+    /* State
+     */
+    const string &str;
+    size_t i;
+    string &err;
+    bool failed;
+    const JsonParse strategy;
+
+    /* fail(msg, err_ret = Json())
+     *
+     * Mark this parse as failed.
+     */
+    Json fail(string &&msg) {
+        return fail(move(msg), Json());
+    }
+
+    template <typename T>
+    T fail(string &&msg, const T err_ret) {
+        if (!failed)
+            err = std::move(msg);
+        failed = true;
+        return err_ret;
+    }
+
+    /* consume_whitespace()
+     *
+     * Advance until the current character is non-whitespace.
+     */
+    void consume_whitespace() {
+        while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
+            i++;
+    }
+
+    /* consume_comment()
+     *
+     * Advance comments (c-style inline and multiline).
+     */
+    bool consume_comment() {
+      bool comment_found = false;
+      if (str[i] == '/') {
+        i++;
+        if (i == str.size())
+          return fail("unexpected end of input after start of comment", false);
+        if (str[i] == '/') { // inline comment
+          i++;
+          // advance until next line, or end of input
+          while (i < str.size() && str[i] != '\n') {
+            i++;
+          }
+          comment_found = true;
+        }
+        else if (str[i] == '*') { // multiline comment
+          i++;
+          if (i > str.size()-2)
+            return fail("unexpected end of input inside multi-line comment", false);
+          // advance until closing tokens
+          while (!(str[i] == '*' && str[i+1] == '/')) {
+            i++;
+            if (i > str.size()-2)
+              return fail(
+                "unexpected end of input inside multi-line comment", false);
+          }
+          i += 2;
+          comment_found = true;
+        }
+        else
+          return fail("malformed comment", false);
+      }
+      return comment_found;
+    }
+
+    /* consume_garbage()
+     *
+     * Advance until the current character is non-whitespace and non-comment.
+     */
+    void consume_garbage() {
+      consume_whitespace();
+      if(strategy == JsonParse::COMMENTS) {
+        bool comment_found = false;
+        do {
+          comment_found = consume_comment();
+          if (failed) return;
+          consume_whitespace();
+        }
+        while(comment_found);
+      }
+    }
+
+    /* get_next_token()
+     *
+     * Return the next non-whitespace character. If the end of the input is reached,
+     * flag an error and return 0.
+     */
+    char get_next_token() {
+        consume_garbage();
+        if (failed) return (char)0;
+        if (i == str.size())
+            return fail("unexpected end of input", (char)0);
+
+        return str[i++];
+    }
+
+    /* encode_utf8(pt, out)
+     *
+     * Encode pt as UTF-8 and add it to out.
+     */
+    void encode_utf8(long pt, string & out) {
+        if (pt < 0)
+            return;
+
+        if (pt < 0x80) {
+            out += static_cast<char>(pt);
+        } else if (pt < 0x800) {
+            out += static_cast<char>((pt >> 6) | 0xC0);
+            out += static_cast<char>((pt & 0x3F) | 0x80);
+        } else if (pt < 0x10000) {
+            out += static_cast<char>((pt >> 12) | 0xE0);
+            out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
+            out += static_cast<char>((pt & 0x3F) | 0x80);
+        } else {
+            out += static_cast<char>((pt >> 18) | 0xF0);
+            out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
+            out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
+            out += static_cast<char>((pt & 0x3F) | 0x80);
+        }
+    }
+
+    /* parse_string()
+     *
+     * Parse a string, starting at the current position.
+     */
+    string parse_string() {
+        string out;
+        long last_escaped_codepoint = -1;
+        while (true) {
+            if (i == str.size())
+                return fail("unexpected end of input in string", "");
+
+            char ch = str[i++];
+
+            if (ch == '"') {
+                encode_utf8(last_escaped_codepoint, out);
+                return out;
+            }
+
+            if (in_range(ch, 0, 0x1f))
+                return fail("unescaped " + esc(ch) + " in string", "");
+
+            // The usual case: non-escaped characters
+            if (ch != '\\') {
+                encode_utf8(last_escaped_codepoint, out);
+                last_escaped_codepoint = -1;
+                out += ch;
+                continue;
+            }
+
+            // Handle escapes
+            if (i == str.size())
+                return fail("unexpected end of input in string", "");
+
+            ch = str[i++];
+
+            if (ch == 'u') {
+                // Extract 4-byte escape sequence
+                string esc = str.substr(i, 4);
+                // Explicitly check length of the substring. The following loop
+                // relies on std::string returning the terminating NUL when
+                // accessing str[length]. Checking here reduces brittleness.
+                if (esc.length() < 4) {
+                    return fail("bad \\u escape: " + esc, "");
+                }
+                for (size_t j = 0; j < 4; j++) {
+                    if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
+                            && !in_range(esc[j], '0', '9'))
+                        return fail("bad \\u escape: " + esc, "");
+                }
+
+                long codepoint = strtol(esc.data(), nullptr, 16);
+
+                // JSON specifies that characters outside the BMP shall be encoded as a pair
+                // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
+                // whether we're in the middle of such a beast: the previous codepoint was an
+                // escaped lead (high) surrogate, and this is a trail (low) surrogate.
+                if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
+                        && in_range(codepoint, 0xDC00, 0xDFFF)) {
+                    // Reassemble the two surrogate pairs into one astral-plane character, per
+                    // the UTF-16 algorithm.
+                    encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
+                                 | (codepoint - 0xDC00)) + 0x10000, out);
+                    last_escaped_codepoint = -1;
+                } else {
+                    encode_utf8(last_escaped_codepoint, out);
+                    last_escaped_codepoint = codepoint;
+                }
+
+                i += 4;
+                continue;
+            }
+
+            encode_utf8(last_escaped_codepoint, out);
+            last_escaped_codepoint = -1;
+
+            if (ch == 'b') {
+                out += '\b';
+            } else if (ch == 'f') {
+                out += '\f';
+            } else if (ch == 'n') {
+                out += '\n';
+            } else if (ch == 'r') {
+                out += '\r';
+            } else if (ch == 't') {
+                out += '\t';
+            } else if (ch == '"' || ch == '\\' || ch == '/') {
+                out += ch;
+            } else {
+                return fail("invalid escape character " + esc(ch), "");
+            }
+        }
+    }
+
+    /* parse_number()
+     *
+     * Parse a double.
+     */
+    Json parse_number() {
+        size_t start_pos = i;
+
+        if (str[i] == '-')
+            i++;
+
+        // Integer part
+        if (str[i] == '0') {
+            i++;
+            if (in_range(str[i], '0', '9'))
+                return fail("leading 0s not permitted in numbers");
+        } else if (in_range(str[i], '1', '9')) {
+            i++;
+            while (in_range(str[i], '0', '9'))
+                i++;
+        } else {
+            return fail("invalid " + esc(str[i]) + " in number");
+        }
+
+        if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
+                && (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
+            return std::atoi(str.c_str() + start_pos);
+        }
+
+        // Decimal part
+        if (str[i] == '.') {
+            i++;
+            if (!in_range(str[i], '0', '9'))
+                return fail("at least one digit required in fractional part");
+
+            while (in_range(str[i], '0', '9'))
+                i++;
+        }
+
+        // Exponent part
+        if (str[i] == 'e' || str[i] == 'E') {
+            i++;
+
+            if (str[i] == '+' || str[i] == '-')
+                i++;
+
+            if (!in_range(str[i], '0', '9'))
+                return fail("at least one digit required in exponent");
+
+            while (in_range(str[i], '0', '9'))
+                i++;
+        }
+
+        return std::strtod(str.c_str() + start_pos, nullptr);
+    }
+
+    /* expect(str, res)
+     *
+     * Expect that 'str' starts at the character that was just read. If it does, advance
+     * the input and return res. If not, flag an error.
+     */
+    Json expect(const string &expected, Json res) {
+        assert(i != 0);
+        i--;
+        if (str.compare(i, expected.length(), expected) == 0) {
+            i += expected.length();
+            return res;
+        } else {
+            return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
+        }
+    }
+
+    /* parse_json()
+     *
+     * Parse a JSON object.
+     */
+    Json parse_json(int depth) {
+        if (depth > max_depth) {
+            return fail("exceeded maximum nesting depth");
+        }
+
+        char ch = get_next_token();
+        if (failed)
+            return Json();
+
+        if (ch == '-' || (ch >= '0' && ch <= '9')) {
+            i--;
+            return parse_number();
+        }
+
+        if (ch == 't')
+            return expect("true", true);
+
+        if (ch == 'f')
+            return expect("false", false);
+
+        if (ch == 'n')
+            return expect("null", Json());
+
+        if (ch == '"')
+            return parse_string();
+
+        if (ch == '{') {
+            map<string, Json> data;
+            ch = get_next_token();
+            if (ch == '}')
+                return data;
+
+            while (1) {
+                if (ch != '"')
+                    return fail("expected '\"' in object, got " + esc(ch));
+
+                string key = parse_string();
+                if (failed)
+                    return Json();
+
+                ch = get_next_token();
+                if (ch != ':')
+                    return fail("expected ':' in object, got " + esc(ch));
+
+                data[std::move(key)] = parse_json(depth + 1);
+                if (failed)
+                    return Json();
+
+                ch = get_next_token();
+                if (ch == '}')
+                    break;
+                if (ch != ',')
+                    return fail("expected ',' in object, got " + esc(ch));
+
+                ch = get_next_token();
+            }
+            return data;
+        }
+
+        if (ch == '[') {
+            vector<Json> data;
+            ch = get_next_token();
+            if (ch == ']')
+                return data;
+
+            while (1) {
+                i--;
+                data.push_back(parse_json(depth + 1));
+                if (failed)
+                    return Json();
+
+                ch = get_next_token();
+                if (ch == ']')
+                    break;
+                if (ch != ',')
+                    return fail("expected ',' in list, got " + esc(ch));
+
+                ch = get_next_token();
+                (void)ch;
+            }
+            return data;
+        }
+
+        return fail("expected value, got " + esc(ch));
+    }
+};
+}//namespace {
+
+Json Json::parse(const string &in, string &err, JsonParse strategy) {
+    JsonParser parser { in, 0, err, false, strategy };
+    Json result = parser.parse_json(0);
+
+    // Check for any trailing garbage
+    parser.consume_garbage();
+    if (parser.failed)
+        return Json();
+    if (parser.i != in.size())
+        return parser.fail("unexpected trailing " + esc(in[parser.i]));
+
+    return result;
+}
+
+// Documented in json11.hpp
+vector<Json> Json::parse_multi(const string &in,
+                               std::string::size_type &parser_stop_pos,
+                               string &err,
+                               JsonParse strategy) {
+    JsonParser parser { in, 0, err, false, strategy };
+    parser_stop_pos = 0;
+    vector<Json> json_vec;
+    while (parser.i != in.size() && !parser.failed) {
+        json_vec.push_back(parser.parse_json(0));
+        if (parser.failed)
+            break;
+
+        // Check for another object
+        parser.consume_garbage();
+        if (parser.failed)
+            break;
+        parser_stop_pos = parser.i;
+    }
+    return json_vec;
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Shape-checking
+ */
+
+bool Json::has_shape(const shape & types, string & err) const {
+    if (!is_object()) {
+        err = "expected JSON object, got " + dump();
+        return false;
+    }
+
+    for (auto & item : types) {
+        if ((*this)[item.first].type() != item.second) {
+            err = "bad type for " + item.first + " in " + dump();
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace json11
diff --git a/examples/validator/json11.hpp b/examples/validator/json11.hpp
new file mode 100644
index 0000000..0c47d05
--- /dev/null
+++ b/examples/validator/json11.hpp
@@ -0,0 +1,232 @@
+/* json11
+ *
+ * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
+ *
+ * The core object provided by the library is json11::Json. A Json object represents any JSON
+ * value: null, bool, number (int or double), string (std::string), array (std::vector), or
+ * object (std::map).
+ *
+ * Json objects act like values: they can be assigned, copied, moved, compared for equality or
+ * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
+ * Json::parse (static) to parse a std::string as a Json object.
+ *
+ * Internally, the various types of Json object are represented by the JsonValue class
+ * hierarchy.
+ *
+ * A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
+ * so some JSON implementations distinguish between integers and floating-point numbers, while
+ * some don't. In json11, we choose the latter. Because some JSON implementations (namely
+ * Javascript itself) treat all numbers as the same type, distinguishing the two leads
+ * to JSON that will be *silently* changed by a round-trip through those implementations.
+ * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
+ * provides integer helpers.
+ *
+ * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
+ * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
+ * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
+ * will be exact for +/- 275 years.)
+ */
+
+/* Copyright (c) 2013 Dropbox, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <map>
+#include <memory>
+#include <initializer_list>
+
+#ifdef _MSC_VER
+    #if _MSC_VER <= 1800 // VS 2013
+        #ifndef noexcept
+            #define noexcept throw()
+        #endif
+
+        #ifndef snprintf
+            #define snprintf _snprintf_s
+        #endif
+    #endif
+#endif
+
+namespace json11 {
+
+enum JsonParse {
+    STANDARD, COMMENTS
+};
+
+class JsonValue;
+
+class Json final {
+public:
+    // Types
+    enum Type {
+        NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT
+    };
+
+    // Array and object typedefs
+    typedef std::vector<Json> array;
+    typedef std::map<std::string, Json> object;
+
+    // Constructors for the various types of JSON value.
+    Json() noexcept;                // NUL
+    Json(std::nullptr_t) noexcept;  // NUL
+    Json(double value);             // NUMBER
+    Json(int value);                // NUMBER
+    Json(bool value);               // BOOL
+    Json(const std::string &value); // STRING
+    Json(std::string &&value);      // STRING
+    Json(const char * value);       // STRING
+    Json(const array &values);      // ARRAY
+    Json(array &&values);           // ARRAY
+    Json(const object &values);     // OBJECT
+    Json(object &&values);          // OBJECT
+
+    // Implicit constructor: anything with a to_json() function.
+    template <class T, class = decltype(&T::to_json)>
+    Json(const T & t) : Json(t.to_json()) {}
+
+    // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
+    template <class M, typename std::enable_if<
+        std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value
+        && std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
+            int>::type = 0>
+    Json(const M & m) : Json(object(m.begin(), m.end())) {}
+
+    // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
+    template <class V, typename std::enable_if<
+        std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
+            int>::type = 0>
+    Json(const V & v) : Json(array(v.begin(), v.end())) {}
+
+    // This prevents Json(some_pointer) from accidentally producing a bool. Use
+    // Json(bool(some_pointer)) if that behavior is desired.
+    Json(void *) = delete;
+
+    // Accessors
+    Type type() const;
+
+    bool is_null()   const { return type() == NUL; }
+    bool is_number() const { return type() == NUMBER; }
+    bool is_bool()   const { return type() == BOOL; }
+    bool is_string() const { return type() == STRING; }
+    bool is_array()  const { return type() == ARRAY; }
+    bool is_object() const { return type() == OBJECT; }
+
+    // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
+    // distinguish between integer and non-integer numbers - number_value() and int_value()
+    // can both be applied to a NUMBER-typed object.
+    double number_value() const;
+    int int_value() const;
+
+    // Return the enclosed value if this is a boolean, false otherwise.
+    bool bool_value() const;
+    // Return the enclosed string if this is a string, "" otherwise.
+    const std::string &string_value() const;
+    // Return the enclosed std::vector if this is an array, or an empty vector otherwise.
+    const array &array_items() const;
+    // Return the enclosed std::map if this is an object, or an empty map otherwise.
+    const object &object_items() const;
+
+    // Return a reference to arr[i] if this is an array, Json() otherwise.
+    const Json & operator[](size_t i) const;
+    // Return a reference to obj[key] if this is an object, Json() otherwise.
+    const Json & operator[](const std::string &key) const;
+
+    // Serialize.
+    void dump(std::string &out) const;
+    std::string dump() const {
+        std::string out;
+        dump(out);
+        return out;
+    }
+
+    // Parse. If parse fails, return Json() and assign an error message to err.
+    static Json parse(const std::string & in,
+                      std::string & err,
+                      JsonParse strategy = JsonParse::STANDARD);
+    static Json parse(const char * in,
+                      std::string & err,
+                      JsonParse strategy = JsonParse::STANDARD) {
+        if (in) {
+            return parse(std::string(in), err, strategy);
+        } else {
+            err = "null input";
+            return nullptr;
+        }
+    }
+    // Parse multiple objects, concatenated or separated by whitespace
+    static std::vector<Json> parse_multi(
+        const std::string & in,
+        std::string::size_type & parser_stop_pos,
+        std::string & err,
+        JsonParse strategy = JsonParse::STANDARD);
+
+    static inline std::vector<Json> parse_multi(
+        const std::string & in,
+        std::string & err,
+        JsonParse strategy = JsonParse::STANDARD) {
+        std::string::size_type parser_stop_pos;
+        return parse_multi(in, parser_stop_pos, err, strategy);
+    }
+
+    bool operator== (const Json &rhs) const;
+    bool operator<  (const Json &rhs) const;
+    bool operator!= (const Json &rhs) const { return !(*this == rhs); }
+    bool operator<= (const Json &rhs) const { return !(rhs < *this); }
+    bool operator>  (const Json &rhs) const { return  (rhs < *this); }
+    bool operator>= (const Json &rhs) const { return !(*this < rhs); }
+
+    /* has_shape(types, err)
+     *
+     * Return true if this is a JSON object and, for each item in types, has a field of
+     * the given type. If not, return false and set err to a descriptive message.
+     */
+    typedef std::initializer_list<std::pair<std::string, Type>> shape;
+    bool has_shape(const shape & types, std::string & err) const;
+
+private:
+    std::shared_ptr<JsonValue> m_ptr;
+};
+
+// Internal class hierarchy - JsonValue objects are not exposed to users of this API.
+class JsonValue {
+protected:
+    friend class Json;
+    friend class JsonInt;
+    friend class JsonDouble;
+    virtual Json::Type type() const = 0;
+    virtual bool equals(const JsonValue * other) const = 0;
+    virtual bool less(const JsonValue * other) const = 0;
+    virtual void dump(std::string &out) const = 0;
+    virtual double number_value() const;
+    virtual int int_value() const;
+    virtual bool bool_value() const;
+    virtual const std::string &string_value() const;
+    virtual const Json::array &array_items() const;
+    virtual const Json &operator[](size_t i) const;
+    virtual const Json::object &object_items() const;
+    virtual const Json &operator[](const std::string &key) const;
+    virtual ~JsonValue() {}
+};
+
+} // namespace json11
diff --git a/examples/validator/tinygltf-validate.cc b/examples/validator/tinygltf-validate.cc
new file mode 100644
index 0000000..faeb463
--- /dev/null
+++ b/examples/validator/tinygltf-validate.cc
@@ -0,0 +1,170 @@
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+
+#include "json11.hpp"
+
+#include "valijson/adapters/json11_adapter.hpp"
+#include "valijson/utils/json11_utils.hpp"
+
+#include "valijson/schema.hpp"
+#include "valijson/schema_parser.hpp"
+#include "valijson/validator.hpp"
+
+static void usage(const char *name) {
+  std::cerr << "Usage: " << name << " <gltf schema dir> <gltf file>\n";
+  std::cerr << "  schema dir is usually : $glTF/specification/2.0/schema\n";
+  std::cerr << "    where $glTF is a directory of https://github.com/KhronosGroup/glTF\n";
+
+  exit(EXIT_FAILURE);
+}
+
+#if 0
+  resolver r(nlohmann::json_schema_draft4::root_schema,
+         nlohmann::json_schema_draft4::root_schema["id"]);
+  schema_refs_.insert(r.schema_refs.begin(), r.schema_refs.end());
+  assert(r.undefined_refs.size() == 0);
+#endif
+
+#if 0
+static void loader(const json_uri &uri, json &schema)
+{
+  std::fstream lf("." + uri.path());
+  if (!lf.good())
+    throw std::invalid_argument("could not open " + uri.url() + " tried with " + uri.path());
+
+  try {
+    lf >> schema;
+  } catch (std::exception &e) {
+    throw e;
+  }
+}
+
+bool validate(const std::string &schema_dir, const std::string &filename)
+{
+  std::string gltf_schema = schema_dir + "/glTF.schema.json";
+
+  std::fstream f(gltf_schema);
+  if (!f.good()) {
+    std::cerr << "could not open " << gltf_schema << " for reading\n";
+    return false;
+  }
+
+  // 1) Read the schema for the document you want to validate
+  json schema;
+  try {
+    f >> schema;
+  } catch (std::exception &e) {
+    std::cerr << e.what() << " at " << f.tellp() << " - while parsing the schema\n";
+    return false;
+  }
+
+  // 2) create the validator and
+  json_validator validator([&schema_dir](const json_uri &uri, json &schema) {
+    std::cout << "uri.url  : " << uri.url() << std::endl;
+    std::cout << "uri.path : " << uri.path() << std::endl;
+
+    std::fstream lf(schema_dir + "/" + uri.path());
+    if (!lf.good())
+      throw std::invalid_argument("could not open " + uri.url() + " tried with " + uri.path());
+
+    try {
+      lf >> schema;
+    } catch (std::exception &e) {
+      throw e;
+    }
+  }, [](const std::string &, const std::string &) {});
+
+  try {
+    // insert this schema as the root to the validator
+    // this resolves remote-schemas, sub-schemas and references via the given loader-function
+    validator.set_root_schema(schema);
+  } catch (std::exception &e) {
+    std::cerr << "setting root schema failed\n";
+    std::cerr << e.what() << "\n";
+  }
+
+  // 3) do the actual validation of the document
+  json document;
+
+  std::fstream d(filename);
+  if (!d.good()) {
+    std::cerr << "could not open " << filename << " for reading\n";
+    return false;
+  }
+
+  try {
+    d >> document;
+    validator.validate(document);
+  } catch (std::exception &e) {
+    std::cerr << "schema validation failed\n";
+    std::cerr << e.what() << " at offset: " << d.tellg() << "\n";
+    return false;
+  }
+
+  std::cerr << "document is valid\n";
+
+  return true;
+
+}
+#endif
+
+bool validate(const std::string &schema_dir, const std::string &filename) {
+  std::string gltf_schema = schema_dir + "/glTF.schema.json";
+
+  // 1) Read the schema for the document you want to validate
+  json11::Json schema_doc;
+  bool ret = valijson::utils::loadDocument(gltf_schema, schema_doc);
+  if (!ret) {
+    std::cerr << "Failed to load schema file : " << gltf_schema << "\n";
+    return false;
+  }
+
+  // 2) Parse JSON schema content using valijson
+  valijson::Schema mySchema;
+  valijson::SchemaParser parser;
+  valijson::adapters::Json11Adapter mySchemaAdapter(schema_doc);
+  parser.populateSchema(mySchemaAdapter, mySchema);
+
+  // 3) Load a document to validate
+  json11::Json target_doc;
+  if (!valijson::utils::loadDocument(filename, target_doc)) {
+    std::cerr << "Failed to load JSON file to validate : " << filename << "\n";
+    return false;
+  }
+
+  valijson::Validator validator;
+  valijson::ValidationResults results;
+  valijson::adapters::Json11Adapter myTargetAdapter(target_doc);
+  if (!validator.validate(mySchema, myTargetAdapter, &results)) {
+    std::cerr << "Validation failed.\n";
+
+    valijson::ValidationResults::Error error;
+    unsigned int errorNum = 1;
+    while (results.popError(error)) {
+      std::cerr << "Error #" << errorNum << std::endl;
+      std::cerr << "  ";
+      for (const std::string &contextElement : error.context) {
+        std::cerr << contextElement << " ";
+      }
+      std::cerr << std::endl;
+      std::cerr << "    - " << error.description << std::endl;
+      ++errorNum;
+    }
+
+    return false;
+  }
+
+  std::cout << "Valid glTF file!\n";
+
+  return true;
+}
+
+int main(int argc, char *argv[]) {
+  if (argc != 3) usage(argv[0]);
+
+  bool ret = validate(argv[1], argv[2]);
+
+  return ret ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/examples/validator/valijson/LICENSE b/examples/validator/valijson/LICENSE
new file mode 100644
index 0000000..77d3816
--- /dev/null
+++ b/examples/validator/valijson/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2016, Tristan Penman
+Copyright (c) 2016, Akamai Technolgies, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/examples/validator/valijson/include/compat/optional.hpp b/examples/validator/valijson/include/compat/optional.hpp
new file mode 100644
index 0000000..3ba123f
--- /dev/null
+++ b/examples/validator/valijson/include/compat/optional.hpp
@@ -0,0 +1,1042 @@
+// Copyright (C) 2011 - 2012 Andrzej Krzemienski.
+//
+// Use, modification, and distribution is subject to 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)
+//
+// The idea and interface is based on Boost.Optional library
+// authored by Fernando Luis Cacciola Carballal
+
+# ifndef ___OPTIONAL_HPP___
+# define ___OPTIONAL_HPP___
+
+# include <utility>
+# include <type_traits>
+# include <initializer_list>
+# include <cassert>
+# include <functional>
+# include <string>
+# include <stdexcept>
+
+# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false
+
+# if defined __GNUC__ // NOTE: GNUC is also defined for Clang
+#   if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)
+#     define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+#   elif (__GNUC__ > 4)
+#     define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+#   endif
+#
+#   if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)
+#     define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___
+#   elif (__GNUC__ > 4)
+#     define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___
+#   endif
+#
+#   if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1)
+#     define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+#   elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)
+#     define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+#   elif (__GNUC__ > 4)
+#     define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+#   endif
+# endif
+#
+# if defined __clang_major__
+#   if (__clang_major__ == 3 && __clang_minor__ >= 5)
+#     define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
+#   elif (__clang_major__ > 3)
+#     define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
+#   endif
+#   if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
+#     define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+#   elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2)
+#     define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+#   endif
+# endif
+#
+# if defined _MSC_VER
+#   if (_MSC_VER >= 1900)
+#     define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+#   endif
+# endif
+
+# if defined __clang__
+#   if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9)
+#     define OPTIONAL_HAS_THIS_RVALUE_REFS 1
+#   else
+#     define OPTIONAL_HAS_THIS_RVALUE_REFS 0
+#   endif
+# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+#   define OPTIONAL_HAS_THIS_RVALUE_REFS 1
+# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+#   define OPTIONAL_HAS_THIS_RVALUE_REFS 1
+# else
+#   define OPTIONAL_HAS_THIS_RVALUE_REFS 0
+# endif
+
+
+# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+#   define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1
+#   define OPTIONAL_CONSTEXPR_INIT_LIST constexpr
+# else
+#   define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0
+#   define OPTIONAL_CONSTEXPR_INIT_LIST
+# endif
+
+# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L)
+#   define OPTIONAL_HAS_MOVE_ACCESSORS 1
+# else
+#   define OPTIONAL_HAS_MOVE_ACCESSORS 0
+# endif
+
+# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr
+# if (defined __cplusplus) && (__cplusplus == 201103L)
+#   define OPTIONAL_MUTABLE_CONSTEXPR
+# else
+#   define OPTIONAL_MUTABLE_CONSTEXPR constexpr
+# endif
+
+namespace std{
+
+    namespace experimental{
+
+        // BEGIN workaround for missing is_trivially_destructible
+# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+        // leave it: it is already there
+# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+        // leave it: it is already there
+# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+        // leave it: it is already there
+# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS
+        // leave it: the user doesn't want it
+# else
+        template <typename T>
+        using is_trivially_destructible = std::has_trivial_destructor<T>;
+# endif
+        // END workaround for missing is_trivially_destructible
+
+# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___)
+        // leave it; our metafunctions are already defined.
+# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+        // leave it; our metafunctions are already defined.
+# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+        // leave it: it is already there
+# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS
+        // leave it: the user doesn't want it
+# else
+
+
+        // workaround for missing traits in GCC and CLANG
+        template <class T>
+        struct is_nothrow_move_constructible
+        {
+            constexpr static bool value = std::is_nothrow_constructible<T, T&&>::value;
+        };
+
+
+        template <class T, class U>
+        struct is_assignable
+        {
+            template <class X, class Y>
+            constexpr static bool has_assign(...) { return false; }
+
+            template <class X, class Y, size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true)) >
+            // the comma operator is necessary for the cases where operator= returns void
+            constexpr static bool has_assign(bool) { return true; }
+
+            constexpr static bool value = has_assign<T, U>(true);
+        };
+
+
+        template <class T>
+        struct is_nothrow_move_assignable
+        {
+            template <class X, bool has_any_move_assign>
+            struct has_nothrow_move_assign {
+    constexpr static bool value = false;
+            };
+
+            template <class X>
+            struct has_nothrow_move_assign<X, true> {
+    constexpr static bool value = noexcept( std::declval<X&>() = std::declval<X&&>() );
+            };
+
+            constexpr static bool value = has_nothrow_move_assign<T, is_assignable<T&, T&&>::value>::value;
+        };
+        // end workaround
+
+
+# endif
+
+
+
+        // 20.5.4, optional for object types
+        template <class T> class optional;
+
+        // 20.5.5, optional for lvalue reference types
+        template <class T> class optional<T&>;
+
+
+        // workaround: std utility functions aren't constexpr yet
+        template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type& t) noexcept
+        {
+            return static_cast<T&&>(t);
+        }
+
+        template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type&& t) noexcept
+        {
+            static_assert(!std::is_lvalue_reference<T>::value, "!!");
+            return static_cast<T&&>(t);
+        }
+
+        template <class T> inline constexpr typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept
+        {
+            return static_cast<typename std::remove_reference<T>::type&&>(t);
+        }
+
+
+#if defined NDEBUG
+# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
+#else
+# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR)))
+#endif
+
+
+        namespace detail_
+        {
+
+            // static_addressof: a constexpr version of addressof
+            template <typename T>
+            struct has_overloaded_addressof
+            {
+                template <class X>
+                constexpr static bool has_overload(...) { return false; }
+
+                template <class X, size_t S = sizeof(std::declval<X&>().operator&()) >
+                constexpr static bool has_overload(bool) { return true; }
+
+                constexpr static bool value = has_overload<T>(true);
+            };
+
+            template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)>
+            constexpr T* static_addressof(T& ref)
+            {
+                return &ref;
+            }
+
+            template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)>
+            T* static_addressof(T& ref)
+            {
+                return std::addressof(ref);
+            }
+
+
+            // the call to convert<A>(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A
+            template <class U>
+            constexpr U convert(U v) { return v; }
+
+        } // namespace detail
+
+
+        constexpr struct trivial_init_t{} trivial_init{};
+
+
+        // 20.5.6, In-place construction
+        constexpr struct in_place_t{} in_place{};
+
+
+        // 20.5.7, Disengaged state indicator
+        struct nullopt_t
+        {
+            struct init{};
+            constexpr explicit nullopt_t(init){}
+        };
+        constexpr nullopt_t nullopt{nullopt_t::init()};
+
+
+        // 20.5.8, class bad_optional_access
+        class bad_optional_access : public logic_error {
+        public:
+            explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {}
+            explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {}
+        };
+
+
+        template <class T>
+        union storage_t
+        {
+            unsigned char dummy_;
+            T value_;
+
+            constexpr storage_t( trivial_init_t ) noexcept : dummy_() {};
+
+            template <class... Args>
+            constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
+
+            ~storage_t(){}
+        };
+
+
+        template <class T>
+        union constexpr_storage_t
+        {
+            unsigned char dummy_;
+            T value_;
+
+            constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {};
+
+            template <class... Args>
+            constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
+
+            ~constexpr_storage_t() = default;
+        };
+
+
+        template <class T>
+        struct optional_base
+        {
+            bool init_;
+            storage_t<T> storage_;
+
+            constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {};
+
+            explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {}
+
+            explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {}
+
+            template <class... Args> explicit optional_base(in_place_t, Args&&... args)
+            : init_(true), storage_(constexpr_forward<Args>(args)...) {}
+
+            template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)>
+            explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
+            : init_(true), storage_(il, std::forward<Args>(args)...) {}
+
+            ~optional_base() { if (init_) storage_.value_.T::~T(); }
+        };
+
+
+        template <class T>
+        struct constexpr_optional_base
+        {
+            bool init_;
+            constexpr_storage_t<T> storage_;
+
+            constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {};
+
+            explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {}
+
+            explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {}
+
+            template <class... Args> explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
+            : init_(true), storage_(constexpr_forward<Args>(args)...) {}
+
+            template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)>
+            OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
+            : init_(true), storage_(il, std::forward<Args>(args)...) {}
+
+            ~constexpr_optional_base() = default;
+        };
+
+        template <class T>
+        using OptionalBase = typename std::conditional<
+        is_trivially_destructible<T>::value,
+        constexpr_optional_base<typename std::remove_const<T>::type>,
+        optional_base<typename std::remove_const<T>::type>
+        >::type;
+
+
+
+        template <class T>
+        class optional : private OptionalBase<T>
+        {
+            static_assert( !std::is_same<typename std::decay<T>::type, nullopt_t>::value, "bad T" );
+            static_assert( !std::is_same<typename std::decay<T>::type, in_place_t>::value, "bad T" );
+
+
+            constexpr bool initialized() const noexcept { return OptionalBase<T>::init_; }
+            typename std::remove_const<T>::type* dataptr() {  return std::addressof(OptionalBase<T>::storage_.value_); }
+            constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase<T>::storage_.value_); }
+
+# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1
+            constexpr const T& contained_val() const& { return OptionalBase<T>::storage_.value_; }
+#   if OPTIONAL_HAS_MOVE_ACCESSORS == 1
+            OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); }
+            OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase<T>::storage_.value_; }
+#   else
+            T& contained_val() & { return OptionalBase<T>::storage_.value_; }
+            T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); }
+#   endif
+# else
+            constexpr const T& contained_val() const { return OptionalBase<T>::storage_.value_; }
+            T& contained_val() { return OptionalBase<T>::storage_.value_; }
+# endif
+
+            void clear() noexcept {
+    if (initialized()) dataptr()->T::~T();
+    OptionalBase<T>::init_ = false;
+            }
+
+            template <class... Args>
+            void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...)))
+            {
+    assert(!OptionalBase<T>::init_);
+    ::new (static_cast<void*>(dataptr())) T(std::forward<Args>(args)...);
+    OptionalBase<T>::init_ = true;
+            }
+
+            template <class U, class... Args>
+            void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...)))
+            {
+    assert(!OptionalBase<T>::init_);
+    ::new (static_cast<void*>(dataptr())) T(il, std::forward<Args>(args)...);
+    OptionalBase<T>::init_ = true;
+            }
+
+        public:
+            typedef T value_type;
+
+            // 20.5.5.1, constructors
+            constexpr optional() noexcept : OptionalBase<T>()  {};
+            constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {};
+
+            optional(const optional& rhs)
+            : OptionalBase<T>()
+            {
+    if (rhs.initialized()) {
+        ::new (static_cast<void*>(dataptr())) T(*rhs);
+        OptionalBase<T>::init_ = true;
+    }
+            }
+
+            optional(optional&& rhs) noexcept(is_nothrow_move_constructible<T>::value)
+            : OptionalBase<T>()
+            {
+    if (rhs.initialized()) {
+        ::new (static_cast<void*>(dataptr())) T(std::move(*rhs));
+        OptionalBase<T>::init_ = true;
+    }
+            }
+
+            constexpr optional(const T& v) : OptionalBase<T>(v) {}
+
+            constexpr optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {}
+
+            template <class... Args>
+            explicit constexpr optional(in_place_t, Args&&... args)
+            : OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {}
+
+            template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)>
+            OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args)
+            : OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {}
+
+            // 20.5.4.2, Destructor
+            ~optional() = default;
+
+            // 20.5.4.3, assignment
+            optional& operator=(nullopt_t) noexcept
+            {
+    clear();
+    return *this;
+            }
+
+            optional& operator=(const optional& rhs)
+            {
+    if      (initialized() == true  && rhs.initialized() == false) clear();
+    else if (initialized() == false && rhs.initialized() == true)  initialize(*rhs);
+    else if (initialized() == true  && rhs.initialized() == true)  contained_val() = *rhs;
+    return *this;
+            }
+
+            optional& operator=(optional&& rhs)
+            noexcept(is_nothrow_move_assignable<T>::value && is_nothrow_move_constructible<T>::value)
+            {
+    if      (initialized() == true  && rhs.initialized() == false) clear();
+        else if (initialized() == false && rhs.initialized() == true)  initialize(std::move(*rhs));
+            else if (initialized() == true  && rhs.initialized() == true)  contained_val() = std::move(*rhs);
+    return *this;
+            }
+
+            template <class U>
+            auto operator=(U&& v)
+            -> typename enable_if
+            <
+            is_same<typename decay<U>::type, T>::value,
+            optional&
+            >::type
+            {
+    if (initialized()) { contained_val() = std::forward<U>(v); }
+    else               { initialize(std::forward<U>(v));  }
+    return *this;
+            }
+
+
+            template <class... Args>
+            void emplace(Args&&... args)
+            {
+    clear();
+    initialize(std::forward<Args>(args)...);
+            }
+
+            template <class U, class... Args>
+            void emplace(initializer_list<U> il, Args&&... args)
+            {
+    clear();
+    initialize<U, Args...>(il, std::forward<Args>(args)...);
+            }
+
+            // 20.5.4.4, Swap
+            void swap(optional<T>& rhs) noexcept(is_nothrow_move_constructible<T>::value && noexcept(swap(declval<T&>(), declval<T&>())))
+            {
+    if      (initialized() == true  && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); }
+    else if (initialized() == false && rhs.initialized() == true)  { initialize(std::move(*rhs)); rhs.clear(); }
+    else if (initialized() == true  && rhs.initialized() == true)  { using std::swap; swap(**this, *rhs); }
+            }
+
+            // 20.5.4.5, Observers
+
+            explicit constexpr operator bool() const noexcept { return initialized(); }
+
+            constexpr T const* operator ->() const {
+    return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr());
+            }
+
+# if OPTIONAL_HAS_MOVE_ACCESSORS == 1
+
+            OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() {
+    assert (initialized());
+    return dataptr();
+            }
+
+            constexpr T const& operator *() const& {
+    return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
+            }
+
+            OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & {
+    assert (initialized());
+    return contained_val();
+            }
+
+            OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && {
+    assert (initialized());
+    return constexpr_move(contained_val());
+            }
+
+            constexpr T const& value() const& {
+    return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
+            }
+
+            OPTIONAL_MUTABLE_CONSTEXPR T& value() & {
+    return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
+            }
+
+            OPTIONAL_MUTABLE_CONSTEXPR T&& value() && {
+    if (!initialized()) throw bad_optional_access("bad optional access");
+        return std::move(contained_val());
+            }
+
+# else
+
+            T* operator ->() {
+    assert (initialized());
+    return dataptr();
+            }
+
+            constexpr T const& operator *() const {
+    return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
+            }
+
+            T& operator *() {
+    assert (initialized());
+    return contained_val();
+            }
+
+            constexpr T const& value() const {
+    return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
+            }
+
+            T& value() {
+    return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
+            }
+
+# endif
+
+# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1
+
+            template <class V>
+            constexpr T value_or(V&& v) const&
+            {
+    return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v));
+            }
+
+#   if OPTIONAL_HAS_MOVE_ACCESSORS == 1
+
+            template <class V>
+            OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) &&
+            {
+    return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
+            }
+
+#   else
+
+            template <class V>
+            T value_or(V&& v) &&
+            {
+    return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
+            }
+
+#   endif
+
+# else
+
+            template <class V>
+            constexpr T value_or(V&& v) const
+            {
+    return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v));
+            }
+
+# endif
+
+        };
+
+
+        template <class T>
+        class optional<T&>
+        {
+            static_assert( !std::is_same<T, nullopt_t>::value, "bad T" );
+            static_assert( !std::is_same<T, in_place_t>::value, "bad T" );
+            T* ref;
+
+        public:
+
+            // 20.5.5.1, construction/destruction
+            constexpr optional() noexcept : ref(nullptr) {}
+
+            constexpr optional(nullopt_t) noexcept : ref(nullptr) {}
+
+            constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {}
+
+            optional(T&&) = delete;
+
+            constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {}
+
+            explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {}
+
+            explicit optional(in_place_t, T&&) = delete;
+
+            ~optional() = default;
+
+            // 20.5.5.2, mutation
+            optional& operator=(nullopt_t) noexcept {
+    ref = nullptr;
+    return *this;
+            }
+
+            // optional& operator=(const optional& rhs) noexcept {
+            // ref = rhs.ref;
+            // return *this;
+            // }
+
+            // optional& operator=(optional&& rhs) noexcept {
+            // ref = rhs.ref;
+            // return *this;
+            // }
+
+            template <typename U>
+            auto operator=(U&& rhs) noexcept
+            -> typename enable_if
+            <
+            is_same<typename decay<U>::type, optional<T&>>::value,
+            optional&
+            >::type
+            {
+    ref = rhs.ref;
+    return *this;
+            }
+
+            template <typename U>
+            auto operator=(U&& rhs) noexcept
+            -> typename enable_if
+            <
+            !is_same<typename decay<U>::type, optional<T&>>::value,
+            optional&
+            >::type
+            = delete;
+
+            void emplace(T& v) noexcept {
+    ref = detail_::static_addressof(v);
+            }
+
+            void emplace(T&&) = delete;
+
+
+            void swap(optional<T&>& rhs) noexcept
+            {
+    std::swap(ref, rhs.ref);
+            }
+
+            // 20.5.5.3, observers
+            constexpr T* operator->() const {
+    return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref);
+            }
+
+            constexpr T& operator*() const {
+    return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref);
+            }
+
+            constexpr T& value() const {
+    return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref);
+            }
+
+            explicit constexpr operator bool() const noexcept {
+    return ref != nullptr;
+            }
+
+            template <class V>
+            constexpr typename decay<T>::type value_or(V&& v) const
+            {
+    return *this ? **this : detail_::convert<typename decay<T>::type>(constexpr_forward<V>(v));
+            }
+        };
+
+
+        template <class T>
+        class optional<T&&>
+        {
+            static_assert( sizeof(T) == 0, "optional rvalue references disallowed" );
+        };
+
+
+        // 20.5.8, Relational operators
+        template <class T> constexpr bool operator==(const optional<T>& x, const optional<T>& y)
+        {
+            return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y;
+        }
+
+        template <class T> constexpr bool operator!=(const optional<T>& x, const optional<T>& y)
+        {
+            return !(x == y);
+        }
+
+        template <class T> constexpr bool operator<(const optional<T>& x, const optional<T>& y)
+        {
+            return (!y) ? false : (!x) ? true : *x < *y;
+        }
+
+        template <class T> constexpr bool operator>(const optional<T>& x, const optional<T>& y)
+        {
+            return (y < x);
+        }
+
+        template <class T> constexpr bool operator<=(const optional<T>& x, const optional<T>& y)
+        {
+            return !(y < x);
+        }
+
+        template <class T> constexpr bool operator>=(const optional<T>& x, const optional<T>& y)
+        {
+            return !(x < y);
+        }
+
+
+        // 20.5.9, Comparison with nullopt
+        template <class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept
+        {
+            return (!x);
+        }
+
+        template <class T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept
+        {
+            return (!x);
+        }
+
+        template <class T> constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept
+        {
+            return bool(x);
+        }
+
+        template <class T> constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept
+        {
+            return bool(x);
+        }
+
+        template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept
+        {
+            return false;
+        }
+
+        template <class T> constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept
+        {
+            return bool(x);
+        }
+
+        template <class T> constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept
+        {
+            return (!x);
+        }
+
+        template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept
+        {
+            return true;
+        }
+
+        template <class T> constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept
+        {
+            return bool(x);
+        }
+
+        template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept
+        {
+            return false;
+        }
+
+        template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept
+        {
+            return true;
+        }
+
+        template <class T> constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept
+        {
+            return (!x);
+        }
+
+
+
+        // 20.5.10, Comparison with T
+        template <class T> constexpr bool operator==(const optional<T>& x, const T& v)
+        {
+            return bool(x) ? *x == v : false;
+        }
+
+        template <class T> constexpr bool operator==(const T& v, const optional<T>& x)
+        {
+            return bool(x) ? v == *x : false;
+        }
+
+        template <class T> constexpr bool operator!=(const optional<T>& x, const T& v)
+        {
+            return bool(x) ? *x != v : true;
+        }
+
+        template <class T> constexpr bool operator!=(const T& v, const optional<T>& x)
+        {
+            return bool(x) ? v != *x : true;
+        }
+
+        template <class T> constexpr bool operator<(const optional<T>& x, const T& v)
+        {
+            return bool(x) ? *x < v : true;
+        }
+
+        template <class T> constexpr bool operator>(const T& v, const optional<T>& x)
+        {
+            return bool(x) ? v > *x : true;
+        }
+
+        template <class T> constexpr bool operator>(const optional<T>& x, const T& v)
+        {
+            return bool(x) ? *x > v : false;
+        }
+
+        template <class T> constexpr bool operator<(const T& v, const optional<T>& x)
+        {
+            return bool(x) ? v < *x : false;
+        }
+
+        template <class T> constexpr bool operator>=(const optional<T>& x, const T& v)
+        {
+            return bool(x) ? *x >= v : false;
+        }
+
+        template <class T> constexpr bool operator<=(const T& v, const optional<T>& x)
+        {
+            return bool(x) ? v <= *x : false;
+        }
+
+        template <class T> constexpr bool operator<=(const optional<T>& x, const T& v)
+        {
+            return bool(x) ? *x <= v : true;
+        }
+
+        template <class T> constexpr bool operator>=(const T& v, const optional<T>& x)
+        {
+            return bool(x) ? v >= *x : true;
+        }
+
+
+        // Comparison of optional<T&> with T
+        template <class T> constexpr bool operator==(const optional<T&>& x, const T& v)
+        {
+            return bool(x) ? *x == v : false;
+        }
+
+        template <class T> constexpr bool operator==(const T& v, const optional<T&>& x)
+        {
+            return bool(x) ? v == *x : false;
+        }
+
+        template <class T> constexpr bool operator!=(const optional<T&>& x, const T& v)
+        {
+            return bool(x) ? *x != v : true;
+        }
+
+        template <class T> constexpr bool operator!=(const T& v, const optional<T&>& x)
+        {
+            return bool(x) ? v != *x : true;
+        }
+
+        template <class T> constexpr bool operator<(const optional<T&>& x, const T& v)
+        {
+            return bool(x) ? *x < v : true;
+        }
+
+        template <class T> constexpr bool operator>(const T& v, const optional<T&>& x)
+        {
+            return bool(x) ? v > *x : true;
+        }
+
+        template <class T> constexpr bool operator>(const optional<T&>& x, const T& v)
+        {
+            return bool(x) ? *x > v : false;
+        }
+
+        template <class T> constexpr bool operator<(const T& v, const optional<T&>& x)
+        {
+            return bool(x) ? v < *x : false;
+        }
+
+        template <class T> constexpr bool operator>=(const optional<T&>& x, const T& v)
+        {
+            return bool(x) ? *x >= v : false;
+        }
+
+        template <class T> constexpr bool operator<=(const T& v, const optional<T&>& x)
+        {
+            return bool(x) ? v <= *x : false;
+        }
+
+        template <class T> constexpr bool operator<=(const optional<T&>& x, const T& v)
+        {
+            return bool(x) ? *x <= v : true;
+        }
+
+        template <class T> constexpr bool operator>=(const T& v, const optional<T&>& x)
+        {
+            return bool(x) ? v >= *x : true;
+        }
+
+        // Comparison of optional<T const&> with T
+        template <class T> constexpr bool operator==(const optional<const T&>& x, const T& v)
+        {
+            return bool(x) ? *x == v : false;
+        }
+
+        template <class T> constexpr bool operator==(const T& v, const optional<const T&>& x)
+        {
+            return bool(x) ? v == *x : false;
+        }
+
+        template <class T> constexpr bool operator!=(const optional<const T&>& x, const T& v)
+        {
+            return bool(x) ? *x != v : true;
+        }
+
+        template <class T> constexpr bool operator!=(const T& v, const optional<const T&>& x)
+        {
+            return bool(x) ? v != *x : true;
+        }
+
+        template <class T> constexpr bool operator<(const optional<const T&>& x, const T& v)
+        {
+            return bool(x) ? *x < v : true;
+        }
+
+        template <class T> constexpr bool operator>(const T& v, const optional<const T&>& x)
+        {
+            return bool(x) ? v > *x : true;
+        }
+
+        template <class T> constexpr bool operator>(const optional<const T&>& x, const T& v)
+        {
+            return bool(x) ? *x > v : false;
+        }
+
+        template <class T> constexpr bool operator<(const T& v, const optional<const T&>& x)
+        {
+            return bool(x) ? v < *x : false;
+        }
+
+        template <class T> constexpr bool operator>=(const optional<const T&>& x, const T& v)
+        {
+            return bool(x) ? *x >= v : false;
+        }
+
+        template <class T> constexpr bool operator<=(const T& v, const optional<const T&>& x)
+        {
+            return bool(x) ? v <= *x : false;
+        }
+
+        template <class T> constexpr bool operator<=(const optional<const T&>& x, const T& v)
+        {
+            return bool(x) ? *x <= v : true;
+        }
+
+        template <class T> constexpr bool operator>=(const T& v, const optional<const T&>& x)
+        {
+            return bool(x) ? v >= *x : true;
+        }
+
+
+        // 20.5.12, Specialized algorithms
+        template <class T>
+        void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)))
+        {
+            x.swap(y);
+        }
+        
+        
+        template <class T>
+        constexpr optional<typename decay<T>::type> make_optional(T&& v)
+        {
+            return optional<typename decay<T>::type>(constexpr_forward<T>(v));
+        }
+        
+        template <class X>
+        constexpr optional<X&> make_optional(reference_wrapper<X> v)
+        {
+            return optional<X&>(v.get());
+        }
+        
+        
+    } // namespace experimental
+} // namespace std
+
+namespace std
+{
+    template <typename T>
+    struct hash<std::experimental::optional<T>>
+    {
+        typedef typename hash<T>::result_type result_type;
+        typedef std::experimental::optional<T> argument_type;
+        
+        constexpr result_type operator()(argument_type const& arg) const {
+            return arg ? std::hash<T>{}(*arg) : result_type{};
+        }
+    };
+    
+    template <typename T>
+    struct hash<std::experimental::optional<T&>>
+    {
+        typedef typename hash<T>::result_type result_type;
+        typedef std::experimental::optional<T&> argument_type;
+        
+        constexpr result_type operator()(argument_type const& arg) const {
+            return arg ? std::hash<T>{}(*arg) : result_type{};
+        }
+    };
+}
+
+# undef TR2_OPTIONAL_REQUIRES
+# undef TR2_OPTIONAL_ASSERTED_EXPRESSION
+
+# endif //___OPTIONAL_HPP___
diff --git a/examples/validator/valijson/include/valijson/adapters/adapter.hpp b/examples/validator/valijson/include/valijson/adapters/adapter.hpp
new file mode 100644
index 0000000..fba50dd
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/adapter.hpp
@@ -0,0 +1,476 @@
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_ADAPTER_HPP
+
+#include <functional>
+
+namespace valijson {
+namespace adapters {
+
+class FrozenValue;
+
+/**
+ * @brief   An interface that encapsulates access to the JSON values provided
+ *          by a JSON parser implementation.
+ *
+ * This interface allows JSON processing code to be parser-agnostic. It provides
+ * functions to access the plain old datatypes (PODs) that are described in the
+ * JSON specification, and callback-based access to the contents of arrays and
+ * objects.
+ *
+ * The interface also defines a set of functions that allow for type-casting and
+ * type-comparison based on value rather than on type.
+ */
+class Adapter
+{
+public:
+
+    /// Typedef for callback function supplied to applyToArray.
+    typedef std::function<bool (const Adapter &)>
+        ArrayValueCallback;
+
+    /// Typedef for callback function supplied to applyToObject.
+    typedef std::function<bool (const std::string &, const Adapter &)>
+        ObjectMemberCallback;
+
+    /**
+     * @brief   Virtual destructor defined to ensure deletion via base-class
+     *          pointers is safe.
+     */
+    virtual ~Adapter() { };
+
+    /**
+     * @brief   Apply a callback function to each value in an array.
+     *
+     * The callback function is invoked for each element in the array, until
+     * it has been applied to all values, or it returns false.
+     *
+     * @param   fn  Callback function to invoke
+     *
+     * @returns true if Adapter contains an array and all values are equal,
+     *          false otherwise.
+     */
+    virtual bool applyToArray(ArrayValueCallback fn) const = 0;
+
+    /**
+     * @brief   Apply a callback function to each member in an object.
+     *
+     * The callback function shall be invoked for each member in the object,
+     * until it has been applied to all values, or it returns false.
+     *
+     * @param   fn  Callback function to invoke
+     *
+     * @returns true if Adapter contains an object, and callback function
+     *          returns true for each member in the object, false otherwise.
+     */
+    virtual bool applyToObject(ObjectMemberCallback fn) const = 0;
+
+    /**
+     * @brief   Return the boolean representation of the contained value.
+     *
+     * This function shall return a boolean value if the Adapter contains either
+     * an actual boolean value, or one of the strings 'true' or 'false'.
+     * The string comparison is case sensitive.
+     *
+     * An exception shall be thrown if the value cannot be cast to a boolean.
+     *
+     * @returns  Boolean representation of contained value.
+     */
+    virtual bool asBool() const = 0;
+
+    /**
+     * @brief   Retrieve the boolean representation of the contained value.
+     *
+     * This function shall retrieve a boolean value if the Adapter contains
+     * either an actual boolean value, or one of the strings 'true' or 'false'.
+     * The string comparison is case sensitive.
+     *
+     * The retrieved value is returned via reference.
+     *
+     * @param   result  reference to a bool to set with retrieved value.
+     *
+     * @returns true if the value could be retrieved, false otherwise
+     */
+    virtual bool asBool(bool &result) const = 0;
+
+    /**
+     * @brief   Return the double representation of the contained value.
+     *
+     * This function shall return a double value if the Adapter contains either
+     * an actual double, an integer, or a string that contains a valid
+     * representation of a numeric value (according to the C++ Std Library).
+     *
+     * An exception shall be thrown if the value cannot be cast to a double.
+     *
+     * @returns  Double representation of contained value.
+     */
+    virtual double asDouble() const = 0;
+
+    /**
+     * @brief   Retrieve the double representation of the contained value.
+     *
+     * This function shall retrieve a double value if the Adapter contains either
+     * an actual double, an integer, or a string that contains a valid
+     * representation of a numeric value (according to the C++ Std Library).
+     *
+     * The retrieved value is returned via reference.
+     *
+     * @param   result  reference to a double to set with retrieved value.
+     *
+     * @returns true if the value could be retrieved, false otherwise
+     */
+    virtual bool asDouble(double &result) const = 0;
+
+    /**
+     * @brief   Return the int64_t representation of the contained value.
+     *
+     * This function shall return an int64_t value if the Adapter contains either
+     * an actual integer, or a string that contains a valid representation of an
+     * integer value (according to the C++ Std Library).
+     *
+     * An exception shall be thrown if the value cannot be cast to an int64_t.
+     *
+     * @returns  int64_t representation of contained value.
+     */
+    virtual int64_t asInteger() const = 0;
+
+    /**
+     * @brief   Retrieve the int64_t representation of the contained value.
+     *
+     * This function shall retrieve an int64_t value if the Adapter contains
+     * either an actual integer, or a string that contains a valid
+     * representation of an integer value (according to the C++ Std Library).
+     *
+     * The retrieved value is returned via reference.
+     *
+     * @param   result  reference to a int64_t to set with retrieved value.
+     *
+     * @returns true if the value could be retrieved, false otherwise
+     */
+    virtual bool asInteger(int64_t &result) const = 0;
+
+    /**
+     * @brief   Return the string representation of the contained value.
+     *
+     * This function shall return a string value if the Adapter contains either
+     * an actual string, a literal value of another POD type, an empty array,
+     * an empty object, or null.
+     *
+     * An exception shall be thrown if the value cannot be cast to a string.
+     *
+     * @returns  string representation of contained value.
+     */
+    virtual std::string asString() const = 0;
+
+    /**
+     * @brief   Retrieve the string representation of the contained value.
+     *
+     * This function shall retrieve a string value if the Adapter contains either
+     * an actual string, a literal value of another POD type, an empty array,
+     * an empty object, or null.
+     *
+     * The retrieved value is returned via reference.
+     *
+     * @param   result  reference to a string to set with retrieved value.
+     *
+     * @returns true if the value could be retrieved, false otherwise
+     */
+    virtual bool asString(std::string &result) const = 0;
+
+    /**
+     * @brief   Compare the value held by this Adapter instance with the value
+     *          held by another Adapter instance.
+     *
+     * @param   other   the other adapter instance
+     * @param   strict  flag to use strict type comparison
+     *
+     * @returns true if values are equal, false otherwise
+     */
+    virtual bool equalTo(const Adapter &other, bool strict) const = 0;
+
+    /**
+     * @brief   Create a new FrozenValue instance that is equivalent to the
+     *          value contained by the Adapter.
+     *
+     * @returns pointer to a new FrozenValue instance, belonging to the caller.
+     */
+    virtual FrozenValue* freeze() const = 0;
+
+    /**
+     * @brief   Return the number of elements in the array.
+     *
+     * Throws an exception if the value is not an array.
+     *
+     * @return  number of elements if value is an array
+     */
+    virtual size_t getArraySize() const = 0;
+
+    /**
+     * @brief   Retrieve the number of elements in the array.
+     *
+     * This function shall return true or false to indicate whether or not the
+     * result value was set. If the contained value is not an array, the
+     * result value shall not be set. This applies even if the value could be
+     * cast to an empty array. The calling code is expected to handles those
+     * cases manually.
+     *
+     * @param   result  reference to size_t variable to set with result.
+     *
+     * @return  true if value retrieved successfully, false otherwise.
+     */
+    virtual bool getArraySize(size_t &result) const = 0;
+
+    /**
+     * @brief   Return the contained boolean value.
+     *
+     * This function shall throw an exception if the contained value is not a
+     * boolean.
+     *
+     * @returns contained boolean value.
+     */
+    virtual bool getBool() const = 0;
+
+    /**
+     * @brief   Retrieve the contained boolean value.
+     *
+     * This function shall retrieve the boolean value contained by this Adapter,
+     * and store it in the result variable that was passed by reference.
+     *
+     * @param   result  reference to boolean variable to set with result.
+     *
+     * @returns true if the value was retrieved, false otherwise.
+     */
+    virtual bool getBool(bool &result) const = 0;
+
+    /**
+     * @brief   Return the contained double value.
+     *
+     * This function shall throw an exception if the contained value is not a
+     * double.
+     *
+     * @returns contained double value.
+     */
+    virtual double getDouble() const = 0;
+
+    /**
+     * @brief   Retrieve the contained double value.
+     *
+     * This function shall retrieve the double value contained by this Adapter,
+     * and store it in the result variable that was passed by reference.
+     *
+     * @param   result  reference to double variable to set with result.
+     *
+     * @returns true if the value was retrieved, false otherwise.
+     */
+    virtual bool getDouble(double &result) const = 0;
+
+    /**
+     * @brief   Return the contained integer value.
+     *
+     * This function shall throw an exception if the contained value is not a
+     * integer.
+     *
+     * @returns contained integer value.
+     */
+    virtual int64_t getInteger() const = 0;
+
+    /**
+     * @brief   Retrieve the contained integer value.
+     *
+     * This function shall retrieve the integer value contained by this Adapter,
+     * and store it in the result variable that was passed by reference.
+     *
+     * @param   result  reference to integer variable to set with result.
+     *
+     * @returns true if the value was retrieved, false otherwise.
+     */
+    virtual bool getInteger(int64_t &result) const = 0;
+
+    /**
+     * @brief   Return the contained numeric value as a double.
+     *
+     * This function shall throw an exception if the contained value is not a
+     * integer or a double.
+     *
+     * @returns contained double or integral value.
+     */
+    virtual double getNumber() const = 0;
+
+    /**
+     * @brief   Retrieve the contained numeric value as a double.
+     *
+     * This function shall retrieve the double or integral value contained by
+     * this Adapter, and store it in the result variable that was passed by
+     * reference.
+     *
+     * @param   result  reference to double variable to set with result.
+     *
+     * @returns true if the value was retrieved, false otherwise.
+     */
+    virtual bool getNumber(double &result) const = 0;
+
+    /**
+     * @brief   Return the number of members in the object.
+     *
+     * Throws an exception if the value is not an object.
+     *
+     * @return  number of members if value is an object
+     */
+    virtual size_t getObjectSize() const = 0;
+
+    /**
+     * @brief   Retrieve the number of members in the object.
+     *
+     * This function shall return true or false to indicate whether or not the
+     * result value was set. If the contained value is not an object, the
+     * result value shall not be set. This applies even if the value could be
+     * cast to an empty object. The calling code is expected to handles those
+     * cases manually.
+     *
+     * @param   result  reference to size_t variable to set with result.
+     *
+     * @return  true if value retrieved successfully, false otherwise.
+     */
+    virtual bool getObjectSize(size_t &result) const = 0;
+
+    /**
+     * @brief   Return the contained string value.
+     *
+     * This function shall throw an exception if the contained value is not a
+     * string - even if the value could be cast to a string. The asString()
+     * function should be used when casting is allowed.
+     *
+     * @returns string contained by this Adapter
+     */
+    virtual std::string getString() const = 0;
+
+    /**
+     * @brief   Retrieve the contained string value.
+     *
+     * This function shall retrieve the string value contained by this Adapter,
+     * and store it in result variable that is passed by reference.
+     *
+     * @param   result  reference to string to set with result
+     *
+     * @returns true if string was retrieved, false otherwise
+     */
+    virtual bool getString(std::string &result) const = 0;
+
+    /**
+     * @brief   Returns whether or not this Adapter supports strict types.
+     *
+     * This function shall return true if the Adapter implementation supports
+     * strict types, or false if the Adapter fails to store any part of the
+     * type information supported by the Adapter interface.
+     *
+     * For example, the PropertyTreeAdapter implementation stores POD values as
+     * strings, effectively discarding any other type information. If you were
+     * to call isDouble() on a double stored by this Adapter, the result would
+     * be false. The maybeDouble(), asDouble() and various related functions
+     * are provided to perform type checking based on value rather than on type.
+     *
+     * The BasicAdapter template class provides implementations for the type-
+     * casting functions so that Adapter implementations are semantically
+     * equivalent in their type-casting behaviour.
+     *
+     * @returns true if Adapter supports strict types, false otherwise
+     */
+    virtual bool hasStrictTypes() const = 0;
+
+    /// Returns true if the contained value is definitely an array.
+    virtual bool isArray() const = 0;
+
+    /// Returns true if the contained value is definitely a boolean.
+    virtual bool isBool() const = 0;
+
+    /// Returns true if the contained value is definitely a double.
+    virtual bool isDouble() const = 0;
+
+    /// Returns true if the contained value is definitely an integer.
+    virtual bool isInteger() const = 0;
+
+    /// Returns true if the contained value is definitely a null.
+    virtual bool isNull() const = 0;
+
+    /// Returns true if the contained value is either a double or an integer.
+    virtual bool isNumber() const = 0;
+
+    /// Returns true if the contained value is definitely an object.
+    virtual bool isObject() const = 0;
+
+    /// Returns true if the contained value is definitely a string.
+    virtual bool isString() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to an array.
+     *
+     * @returns true if the contained value is an array, an empty string, or an
+     *          empty object.
+     */
+    virtual bool maybeArray() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to a boolean.
+     *
+     * @returns true if the contained value is a boolean, or one of the strings
+     *          'true' or 'false'. Note that numeric values are not to be cast
+     *          to boolean values.
+     */
+    virtual bool maybeBool() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to a double.
+     *
+     * @returns true if the contained value is a double, an integer, or a string
+     *          containing a double or integral value.
+     */
+    virtual bool maybeDouble() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to an integer.
+     *
+     * @returns true if the contained value is an integer, or a string
+     *          containing an integral value.
+     */
+    virtual bool maybeInteger() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to a null.
+     *
+     * @returns true if the contained value is null or an empty string.
+     */
+    virtual bool maybeNull() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to an object.
+     *
+     * @returns true if the contained value is an object, an empty array or
+     *          an empty string.
+     */
+    virtual bool maybeObject() const = 0;
+
+    /**
+     * @brief   Returns true if the contained value can be cast to a string.
+     *
+     * @returns true if the contained value is a non-null POD type, an empty
+     *          array, or an empty object.
+     */
+    virtual bool maybeString() const = 0;
+};
+
+/**
+ * @brief  Template struct that should be specialised for each concrete Adapter
+ *         class.
+ *
+ * @deprecated  This is a bit of a hack, and I'd like to remove it.
+ */
+template<typename T>
+struct AdapterTraits
+{
+
+};
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/basic_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/basic_adapter.hpp
new file mode 100644
index 0000000..28b188c
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/basic_adapter.hpp
@@ -0,0 +1,868 @@
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_BASIC_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_BASIC_ADAPTER_HPP
+
+#include <stdint.h>
+#include <sstream>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/internal/optional.hpp>
+
+namespace valijson {
+namespace adapters {
+
+/**
+ * @brief  A helper for the array and object member iterators.
+ *
+ * See http://www.stlsoft.org/doc-1.9/group__group____pattern____dereference__proxy.html
+ * for motivation
+ *
+ * @tparam Value  Name of the value type
+ */
+template<class Value>
+struct DerefProxy
+{
+    explicit DerefProxy(const Value& x)
+      : m_ref(x) { }
+
+    Value* operator->()
+    {
+        return std::addressof(m_ref);
+    }
+
+    operator Value*()
+    {
+        return std::addressof(m_ref);
+    }
+
+private:
+    Value m_ref;
+};
+
+/**
+ * @brief  Template class that implements the expected semantics of an Adapter.
+ *
+ * Implementing all of the type-casting functionality for each Adapter is error
+ * prone and tedious, so this template class aims to minimise the duplication
+ * of code between various Adapter implementations. This template doesn't quite
+ * succeed in removing all duplication, but it has greatly simplified the
+ * implementation of a new Adapter by encapsulating the type-casting semantics
+ * and a lot of the trivial functionality associated with the Adapter interface.
+ *
+ * By inheriting from this template class, Adapter implementations will inherit
+ * the exception throwing behaviour that is expected by other parts of the
+ * Valijson library.
+ *
+ * @tparam  AdapterType       Self-referential name of the Adapter being
+ *                            specialised.
+ * @tparam  ArrayType         Name of the type that will be returned by the
+ *                            getArray() function. Instances of this type should
+ *                            provide begin(), end() and size() functions so
+ *                            that it is possible to iterate over the values in
+ *                            the array.
+ * @tparam  ObjectMemberType  Name of the type exposed when iterating over the
+ *                            contents of an object returned by getObject().
+ * @tparam  ObjectType        Name of the type that will be returned by the
+ *                            getObject() function. Instances of this type
+ *                            should provide begin(), end(), find() and size()
+ *                            functions so that it is possible to iterate over
+ *                            the members of the object.
+ * @tparam  ValueType         Name of the type that provides a consistent
+ *                            interface to a JSON value for a parser. For
+ *                            example, this type should provide the getDouble()
+ *                            and isDouble() functions. But it does not need to
+ *                            know how to cast values from one type to another -
+ *                            that functionality is provided by this template
+ *                            class.
+ */
+template<
+    typename AdapterType,
+    typename ArrayType,
+    typename ObjectMemberType,
+    typename ObjectType,
+    typename ValueType>
+class BasicAdapter: public Adapter
+{
+protected:
+
+    /**
+     * @brief   Functor for comparing two arrays.
+     *
+     * This functor is used to compare the elements in an array of the type
+     * ArrayType with individual values provided as generic Adapter objects.
+     * Comparison is performed by the () operator.
+     *
+     * The functor works by maintaining an iterator for the current position
+     * in an array. Each time the () operator is called, the value at this
+     * position is compared with the value passed as an argument to ().
+     * Immediately after the comparison, the iterator will be incremented.
+     *
+     * This functor is designed to be passed to the applyToArray() function
+     * of an Adapter object.
+     */
+    class ArrayComparisonFunctor
+    {
+    public:
+
+        /**
+         * @brief   Construct an ArrayComparisonFunctor for an array.
+         *
+         * @param   array   Array to compare values against
+         * @param   strict  Flag to use strict type comparison
+         */
+        ArrayComparisonFunctor(const ArrayType &array, bool strict)
+          : itr(array.begin()),
+            end(array.end()),
+            strict(strict) { }
+
+        /**
+         * @brief   Compare a value against the current element in the array.
+         *
+         * @param   adapter  Value to be compared with current element
+         *
+         * @returns true if values are equal, false otherwise.
+         */
+        bool operator()(const Adapter &adapter)
+        {
+            if (itr == end) {
+                return false;
+            }
+
+            return AdapterType(*itr++).equalTo(adapter, strict);
+        }
+
+    private:
+
+        /// Iterator for current element in the array
+        typename ArrayType::const_iterator itr;
+
+        /// Iterator for one-past the last element of the array
+        typename ArrayType::const_iterator end;
+
+        /// Flag to use strict type comparison
+        const bool strict;
+    };
+
+    /**
+     * @brief   Functor for comparing two objects
+     *
+     * This functor is used to compare the members of an object of the type
+     * ObjectType with key-value pairs belonging to another object.
+     *
+     * The functor works by maintaining a reference to an object provided via
+     * the constructor. When time the () operator is called with a key-value
+     * pair as arguments, the function will attempt to find the key in the
+     * base object. If found, the associated value will be compared with the
+     * value provided to the () operator.
+     *
+     * This functor is designed to be passed to the applyToObject() function
+     * of an Adapter object.
+     */
+    class ObjectComparisonFunctor
+    {
+    public:
+
+        /**
+         * @brief   Construct a new ObjectComparisonFunctor for an object.
+         *
+         * @param   object  object to use as comparison baseline
+         * @param   strict  flag to use strict type-checking
+         */
+        ObjectComparisonFunctor(
+            const ObjectType &object, bool strict)
+          : object(object),
+            strict(strict) { }
+
+        /**
+         * @brief   Find a key in the object and compare its value.
+         *
+         * @param   key    Key to find
+         * @param   value  Value to be compared against
+         *
+         * @returns true if key is found and values are equal, false otherwise.
+         */
+        bool operator()(const std::string &key, const Adapter &value)
+        {
+            const typename ObjectType::const_iterator itr = object.find(key);
+            if (itr == object.end()) {
+                return false;
+            }
+
+            return (*itr).second.equalTo(value, strict);
+        }
+
+    private:
+
+        /// Object to be used as a comparison baseline
+        const ObjectType &object;
+
+        /// Flag to use strict type-checking
+        bool strict;
+    };
+
+
+public:
+
+    /// Alias for ArrayType template parameter
+    typedef ArrayType Array;
+
+    /// Alias for ObjectMemberType template parameter
+    typedef ObjectMemberType ObjectMember;
+
+    /// Alias for ObjectType template parameter
+    typedef ObjectType Object;
+
+    /**
+     * @brief   Construct an Adapter using the default value.
+     *
+     * This constructor relies on the default constructor of the ValueType
+     * class provided as a template argument.
+     */
+    BasicAdapter() { }
+
+    /**
+     * @brief   Construct an Adapter using a specified ValueType object.
+     *
+     * This constructor relies on the copy constructor of the ValueType
+     * class provided as template argument.
+     */
+    BasicAdapter(const ValueType &value)
+      : value(value) { }
+
+    virtual bool applyToArray(ArrayValueCallback fn) const
+    {
+        if (!maybeArray()) {
+            return false;
+        }
+
+        // Due to the fact that the only way a value can be 'maybe an array' is
+        // if it is an empty string or empty object, we only need to go to
+        // effort of constructing an ArrayType instance if the value is
+        // definitely an array.
+        if (value.isArray()) {
+            const opt::optional<Array> array = value.getArrayOptional();
+            for (const AdapterType element : *array) {
+                if (!fn(element)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    virtual bool applyToObject(ObjectMemberCallback fn) const
+    {
+        if (!maybeObject()) {
+            return false;
+        }
+
+        if (value.isObject()) {
+            const opt::optional<Object> object = value.getObjectOptional();
+            for (const ObjectMemberType member : *object) {
+                if (!fn(member.first, AdapterType(member.second))) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Return an ArrayType instance containing an array representation
+     *          of the value held by this Adapter.
+     *
+     * This is a convenience function that is not actually declared in the
+     * Adapter interface, but allows for useful techniques such as procedural
+     * iteration over the elements in an array. The ArrayType instance that is
+     * returned by this function is compatible with the BOOST_FOREACH macro.
+     *
+     * If the contained value is either an empty object, or an empty string,
+     * then this function will cast the value to an empty array.
+     *
+     * @returns ArrayType instance containing an array representation of the
+     *          value held by this Adapter.
+     */
+    ArrayType asArray() const
+    {
+        if (value.isArray()) {
+            return *value.getArrayOptional();
+        } else if (value.isObject()) {
+            size_t objectSize;
+            if (value.getObjectSize(objectSize) && objectSize == 0) {
+                return ArrayType();
+            }
+        } else if (value.isString()) {
+            std::string stringValue;
+            if (value.getString(stringValue) && stringValue.empty()) {
+                return ArrayType();
+            }
+        }
+
+        throw std::runtime_error("JSON value cannot be cast to an array.");
+    }
+
+    virtual bool asBool() const
+    {
+        bool result;
+        if (asBool(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value cannot be cast to a boolean.");
+    }
+
+    virtual bool asBool(bool &result) const
+    {
+        if (value.isBool()) {
+            return value.getBool(result);
+        } else if (value.isString()) {
+            std::string s;
+            if (value.getString(s)) {
+                if (s.compare("true") == 0) {
+                    result = true;
+                    return true;
+                } else if (s.compare("false") == 0) {
+                    result = false;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    virtual double asDouble() const
+    {
+        double result;
+        if (asDouble(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value cannot be cast to a double.");
+    }
+
+    virtual bool asDouble(double &result) const
+    {
+        if (value.isDouble()) {
+            return value.getDouble(result);
+        } else if (value.isInteger()) {
+            int64_t i;
+            if (value.getInteger(i)) {
+                result = double(i);
+                return true;
+            }
+        } else if (value.isString()) {
+            std::string s;
+            if (value.getString(s)) {
+                const char *b = s.c_str();
+                char *e = NULL;
+                double x = strtod(b, &e);
+                if (e == b || e != b + s.length()) {
+                    return false;
+                }
+                result = x;
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    virtual int64_t asInteger() const
+    {
+        int64_t result;
+        if (asInteger(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value cannot be cast as an integer.");
+    }
+
+    virtual bool asInteger(int64_t &result) const
+    {
+        if (value.isInteger()) {
+            return value.getInteger(result);
+        } else if (value.isString()) {
+            std::string s;
+            if (value.getString(s)) {
+                std::istringstream i(s);
+                int64_t x;
+                char c;
+                if (!(!(i >> x) || i.get(c))) {
+                    result = x;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Return an ObjectType instance containing an array representation
+     *          of the value held by this Adapter.
+     *
+     * This is a convenience function that is not actually declared in the
+     * Adapter interface, but allows for useful techniques such as procedural
+     * iteration over the members of the object. The ObjectType instance that is
+     * returned by this function is compatible with the BOOST_FOREACH macro.
+     *
+     * @returns ObjectType instance containing an object representation of the
+     *          value held by this Adapter.
+     */
+    ObjectType asObject() const
+    {
+        if (value.isObject()) {
+            return *value.getObjectOptional();
+        } else if (value.isArray()) {
+            size_t arraySize;
+            if (value.getArraySize(arraySize) && arraySize == 0) {
+                return ObjectType();
+            }
+        } else if (value.isString()) {
+            std::string stringValue;
+            if (value.getString(stringValue) && stringValue.empty()) {
+                return ObjectType();
+            }
+        }
+
+        throw std::runtime_error("JSON value cannot be cast to an object.");
+    }
+
+    virtual std::string asString() const
+    {
+        std::string result;
+        if (asString(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value cannot be cast to a string.");
+    }
+
+    virtual bool asString(std::string &result) const
+    {
+        if (value.isString()) {
+            return value.getString(result);
+        } else if (value.isNull()) {
+            result.clear();
+            return true;
+        } else if (value.isArray()) {
+            size_t arraySize;
+            if (value.getArraySize(arraySize) && arraySize == 0) {
+                result.clear();
+                return true;
+            }
+        } else if (value.isObject()) {
+            size_t objectSize;
+            if (value.getObjectSize(objectSize) && objectSize == 0) {
+                result.clear();
+                return true;
+            }
+        } else if (value.isBool()) {
+            bool boolValue;
+            if (value.getBool(boolValue)) {
+                result = boolValue ? "true" : "false";
+                return true;
+            }
+        } else if (value.isInteger()) {
+            int64_t integerValue;
+            if (value.getInteger(integerValue)) {
+                result = std::to_string(integerValue);
+                return true;
+            }
+        } else if (value.isDouble()) {
+            double doubleValue;
+            if (value.getDouble(doubleValue)) {
+                result = std::to_string(doubleValue);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const
+    {
+        if (isNull() || (!strict && maybeNull())) {
+            return other.isNull() || (!strict && other.maybeNull());
+        } else if (isBool() || (!strict && maybeBool())) {
+            return (other.isBool() || (!strict && other.maybeBool())) &&
+                other.asBool() == asBool();
+        } else if (isNumber() && strict) {
+            return other.isNumber() && other.getNumber() == getNumber();
+        } else if (!strict && maybeDouble()) {
+            return (other.maybeDouble() &&
+                    other.asDouble() == asDouble());
+        } else if (!strict && maybeInteger()) {
+            return (other.maybeInteger() &&
+                    other.asInteger() == asInteger());
+        } else if (isString() || (!strict && maybeString())) {
+            return (other.isString() || (!strict && other.maybeString())) &&
+                other.asString() == asString();
+        } else if (isArray()) {
+            if (other.isArray() && getArraySize() == other.getArraySize()) {
+                const opt::optional<ArrayType> array = value.getArrayOptional();
+                if (array) {
+                    ArrayComparisonFunctor fn(*array, strict);
+                    return other.applyToArray(fn);
+                }
+            } else if (!strict && other.maybeArray() && getArraySize() == 0) {
+                return true;
+            }
+        } else if (isObject()) {
+            if (other.isObject() && other.getObjectSize() == getObjectSize()) {
+                const opt::optional<ObjectType> object = value.getObjectOptional();
+                if (object) {
+                    ObjectComparisonFunctor fn(*object, strict);
+                    return other.applyToObject(fn);
+                }
+            } else if (!strict && other.maybeObject() && getObjectSize() == 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Return an ArrayType instance representing the array contained
+     *          by this Adapter instance.
+     *
+     * This is a convenience function that is not actually declared in the
+     * Adapter interface, but allows for useful techniques such as procedural
+     * iteration over the elements in an array. The ArrayType instance that is
+     * returned by this function is compatible with the BOOST_FOREACH macro.
+     *
+     * If the contained is not an array, this function will throw an exception.
+     *
+     * @returns ArrayType instance containing an array representation of the
+     *          value held by this Adapter.
+     */
+    ArrayType getArray() const
+    {
+        opt::optional<ArrayType> arrayValue = value.getArrayOptional();
+        if (arrayValue) {
+            return *arrayValue;
+        }
+
+        throw std::runtime_error("JSON value is not an array.");
+    }
+
+    virtual size_t getArraySize() const
+    {
+        size_t result;
+        if (value.getArraySize(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not an array.");
+    }
+
+    virtual bool getArraySize(size_t &result) const
+    {
+        return value.getArraySize(result);
+    }
+
+    virtual bool getBool() const
+    {
+        bool result;
+        if (getBool(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not a boolean.");
+    }
+
+    virtual bool getBool(bool &result) const
+    {
+        return value.getBool(result);
+    }
+
+    virtual double getDouble() const
+    {
+        double result;
+        if (getDouble(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not a double.");
+    }
+
+    virtual bool getDouble(double &result) const
+    {
+        return value.getDouble(result);
+    }
+
+    virtual int64_t getInteger() const
+    {
+        int64_t result;
+        if (getInteger(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not an integer.");
+    }
+
+    virtual bool getInteger(int64_t &result) const
+    {
+        return value.getInteger(result);
+    }
+
+    virtual double getNumber() const
+    {
+        double result;
+        if (getNumber(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not a number.");
+    }
+
+    virtual bool getNumber(double &result) const
+    {
+        if (isDouble()) {
+            return getDouble(result);
+        } else if (isInteger()) {
+            int64_t integerResult;
+            if (getInteger(integerResult)) {
+                result = static_cast<double>(integerResult);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Return an ObjectType instance representing the object contained
+     *          by this Adapter instance.
+     *
+     * This is a convenience function that is not actually declared in the
+     * Adapter interface, but allows for useful techniques such as procedural
+     * iteration over the members of an object. The ObjectType instance that is
+     * returned by this function is compatible with the BOOST_FOREACH macro.
+     *
+     * If the contained is not an object, this function will throw an exception.
+     *
+     * @returns ObjectType instance containing an array representation of the
+     *          value held by this Adapter.
+     */
+    ObjectType getObject() const
+    {
+        opt::optional<ObjectType> objectValue = value.getObjectOptional();
+        if (objectValue) {
+            return *objectValue;
+        }
+
+        throw std::runtime_error("JSON value is not an object.");
+    }
+
+    virtual size_t getObjectSize() const
+    {
+        size_t result;
+        if (getObjectSize(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not an object.");
+    }
+
+    virtual bool getObjectSize(size_t &result) const
+    {
+        return value.getObjectSize(result);
+    }
+
+    virtual std::string getString() const
+    {
+        std::string result;
+        if (getString(result)) {
+            return result;
+        }
+
+        throw std::runtime_error("JSON value is not a string.");
+    }
+
+    virtual bool getString(std::string &result) const
+    {
+        return value.getString(result);
+    }
+
+    virtual FrozenValue * freeze() const
+    {
+        return value.freeze();
+    }
+
+    virtual bool hasStrictTypes() const
+    {
+        return ValueType::hasStrictTypes();
+    }
+
+    virtual bool isArray() const
+    {
+        return value.isArray();
+    }
+
+    virtual bool isBool() const
+    {
+        return value.isBool();
+    }
+
+    virtual bool isDouble() const
+    {
+        return value.isDouble();
+    }
+
+    virtual bool isInteger() const
+    {
+        return value.isInteger();
+    }
+
+    virtual bool isNull() const
+    {
+        return value.isNull();
+    }
+
+    virtual bool isNumber() const
+    {
+        return value.isInteger() || value.isDouble();
+    }
+
+    virtual bool isObject() const
+    {
+        return value.isObject();
+    }
+
+    virtual bool isString() const
+    {
+        return value.isString();
+    }
+
+    virtual bool maybeArray() const
+    {
+        if (value.isArray()) {
+            return true;
+        } else if (value.isObject()) {
+            size_t objectSize;
+            if (value.getObjectSize(objectSize) && objectSize == 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool maybeBool() const
+    {
+        if (value.isBool()) {
+            return true;
+        } else if (value.isString()) {
+            std::string stringValue;
+            if (value.getString(stringValue)) {
+                if (stringValue.compare("true") == 0 || stringValue.compare("false") == 0) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool maybeDouble() const
+    {
+        if (value.isNumber()) {
+            return true;
+        } else if (value.isString()) {
+            std::string s;
+            if (value.getString(s)) {
+                const char *b = s.c_str();
+                char *e = NULL;
+                strtod(b, &e);
+                return e != b && e == b + s.length();
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool maybeInteger() const
+    {
+        if (value.isInteger()) {
+            return true;
+        } else if (value.isString()) {
+            std::string s;
+            if (value.getString(s)) {
+                std::istringstream i(s);
+                int64_t x;
+                char c;
+                if (!(i >> x) || i.get(c)) {
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool maybeNull() const
+    {
+        if (value.isNull()) {
+            return true;
+        } else if (value.isString()) {
+            std::string stringValue;
+            if (value.getString(stringValue)) {
+                if (stringValue.empty()) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool maybeObject() const
+    {
+        if (value.isObject()) {
+            return true;
+        } else if (value.isArray()) {
+            size_t arraySize;
+            if (value.getArraySize(arraySize) && arraySize == 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    virtual bool maybeString() const
+    {
+        if (value.isString() || value.isBool() || value.isInteger() ||
+            value.isDouble()) {
+            return true;
+        } else if (value.isObject()) {
+            size_t objectSize;
+            if (value.getObjectSize(objectSize) && objectSize == 0) {
+                return true;
+            }
+        } else if (value.isArray()) {
+            size_t arraySize;
+            if (value.getArraySize(arraySize) && arraySize == 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+private:
+
+    const ValueType value;
+
+};
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/frozen_value.hpp b/examples/validator/valijson/include/valijson/adapters/frozen_value.hpp
new file mode 100644
index 0000000..1b6aa11
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/frozen_value.hpp
@@ -0,0 +1,56 @@
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_FROZEN_VALUE_HPP
+#define __VALIJSON_ADAPTERS_FROZEN_VALUE_HPP
+
+#include <valijson/adapters/adapter.hpp>
+
+namespace valijson {
+namespace adapters {
+
+/**
+ * @brief   An interface that provides minimal access to a stored JSON value.
+ *
+ * The main reason that this interface exists is to support the 'enum'
+ * constraint. Each Adapter type is expected to provide an implementation of
+ * this interface. That class should be able to maintain its own copy of a
+ * JSON value, independent of the original document.
+ *
+ * This interface currently provides just the clone and equalTo functions, but
+ * could be expanded to include other functions declared in the Adapter
+ * interface.
+ *
+ * @todo  it would be nice to better integrate this with the Adapter interface
+ */
+class FrozenValue
+{
+public:
+
+    /**
+     * @brief   Virtual destructor defined to ensure deletion via base-class
+     *          pointers is safe.
+     */
+    virtual ~FrozenValue() { }
+
+    /**
+     * @brief   Clone the stored value and return a pointer to a new FrozenValue
+     *          object containing the value.
+     */
+    virtual FrozenValue *clone() const = 0;
+
+    /**
+     * @brief   Return true if the stored value is equal to the value contained
+     *          by an Adapter instance.
+     *
+     * @param   adapter  Adapter to compare value against
+     * @param   strict   Flag to use strict type comparison
+     *
+     * @returns true if values are equal, false otherwise
+     */
+    virtual bool equalTo(const Adapter &adapter, bool strict) const = 0;
+
+};
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/json11_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/json11_adapter.hpp
new file mode 100644
index 0000000..d913679
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/json11_adapter.hpp
@@ -0,0 +1,713 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the json11 parser library.
+ *
+ * Include this file in your program to enable support for json11.
+ *
+ * This file defines the following classes (not in this order):
+ *  - Json11Adapter
+ *  - Json11Array
+ *  - Json11ArrayValueIterator
+ *  - Json11FrozenValue
+ *  - Json11Object
+ *  - Json11ObjectMember
+ *  - Json11ObjectMemberIterator
+ *  - Json11Value
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is Json11Adapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_JSON11_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_JSON11_ADAPTER_HPP
+
+#include <string>
+#include <json11.hpp>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+class Json11Adapter;
+class Json11ArrayValueIterator;
+class Json11ObjectMemberIterator;
+
+typedef std::pair<std::string, Json11Adapter> Json11ObjectMember;
+
+/**
+ * @brief  Light weight wrapper for a Json11 array value.
+ *
+ * This class is light weight wrapper for a Json11 array. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * Json11 value, assumed to be an array, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class Json11Array
+{
+public:
+
+    typedef Json11ArrayValueIterator const_iterator;
+    typedef Json11ArrayValueIterator iterator;
+
+    /// Construct a Json11Array referencing an empty array.
+    Json11Array()
+      : value(emptyArray()) { }
+
+    /**
+     * @brief   Construct a Json11Array referencing a specific Json11
+     *          value.
+     *
+     * @param   value   reference to a Json11 value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an array.
+     */
+    Json11Array(const json11::Json &value)
+      : value(value)
+    {
+        if (!value.is_array()) {
+            throw std::runtime_error("Value is not an array.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for the first element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying Json11 implementation.
+     */
+    Json11ArrayValueIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for one-past the last element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying Json11 implementation.
+     */
+    Json11ArrayValueIterator end() const;
+
+    /// Return the number of elements in the array
+    size_t size() const
+    {
+        return value.array_items().size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a Json11 value that is an empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const json11::Json & emptyArray()
+    {
+        static const json11::Json array((json11::Json::array()));
+        return array;
+    }
+
+    /// Reference to the contained value
+    const json11::Json &value;
+};
+
+/**
+ * @brief  Light weight wrapper for a Json11 object.
+ *
+ * This class is light weight wrapper for a Json11 object. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * Json11 value, assumed to be an object, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class Json11Object
+{
+public:
+
+    typedef Json11ObjectMemberIterator const_iterator;
+    typedef Json11ObjectMemberIterator iterator;
+
+    /// Construct a Json11Object referencing an empty object singleton.
+    Json11Object()
+      : value(emptyObject()) { }
+
+    /**
+     * @brief   Construct a Json11Object referencing a specific Json11
+     *          value.
+     *
+     * @param   value  reference to a Json11 value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an object.
+     */
+    Json11Object(const json11::Json &value)
+      : value(value)
+    {
+        if (!value.is_object()) {
+            throw std::runtime_error("Value is not an object.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying Json11 implementation.
+     */
+    Json11ObjectMemberIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying Json11 implementation.
+     */
+    Json11ObjectMemberIterator end() const;
+
+    /**
+     * @brief   Return an iterator for the object member with the specified
+     *          property name.
+     *
+     * If an object member with the specified name does not exist, the iterator
+     * returned will be the same as the iterator returned by the end() function.
+     *
+     * @param   propertyName  property name to search for
+     */
+    Json11ObjectMemberIterator find(const std::string &propertyName) const;
+
+    /// Returns the number of members belonging to this object.
+    size_t size() const
+    {
+        return value.object_items().size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a Json11 value that is empty object.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const json11::Json & emptyObject()
+    {
+        static const json11::Json object((json11::Json::object()));
+        return object;
+    }
+
+    /// Reference to the contained object
+    const json11::Json &value;
+};
+
+/**
+ * @brief   Stores an independent copy of a Json11 value.
+ *
+ * This class allows a Json11 value to be stored independent of its original
+ * document. Json11 makes this easy to do, as it does not perform any
+ * custom memory management.
+ *
+ * @see FrozenValue
+ */
+class Json11FrozenValue: public FrozenValue
+{
+public:
+
+    /**
+     * @brief  Make a copy of a Json11 value
+     *
+     * @param  source  the Json11 value to be copied
+     */
+    explicit Json11FrozenValue(const json11::Json &source)
+      : value(source) { }
+
+    virtual FrozenValue * clone() const
+    {
+        return new Json11FrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /// Stored Json11 value
+    json11::Json value;
+};
+
+/**
+ * @brief   Light weight wrapper for a Json11 value.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a Json11 value. This class is responsible
+ * for the mechanics of actually reading a Json11 value, whereas the
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+class Json11Value
+{
+public:
+
+    /// Construct a wrapper for the empty object singleton
+    Json11Value()
+      : value(emptyObject()) { }
+
+    /// Construct a wrapper for a specific Json11 value
+    Json11Value(const json11::Json &value)
+      : value(value) { }
+
+    /**
+     * @brief   Create a new Json11FrozenValue instance that contains the
+     *          value referenced by this Json11Value instance.
+     *
+     * @returns pointer to a new Json11FrozenValue instance, belonging to the
+     *          caller.
+     */
+    FrozenValue * freeze() const
+    {
+        return new Json11FrozenValue(value);
+    }
+
+    /**
+     * @brief   Optionally return a Json11Array instance.
+     *
+     * If the referenced Json11 value is an array, this function will return
+     * a std::optional containing a Json11Array instance referencing the
+     * array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<Json11Array> getArrayOptional() const
+    {
+        if (value.is_array()) {
+            return opt::make_optional(Json11Array(value));
+        }
+
+        return opt::optional<Json11Array>();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced Json11 value is an array, this function will
+     * retrieve the number of elements in the array and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (value.is_array()) {
+            result = value.array_items().size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &result) const
+    {
+        if (value.is_bool()) {
+            result = value.bool_value();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getDouble(double &result) const
+    {
+        if (value.is_number()) {
+            result = value.number_value();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getInteger(int64_t &result) const
+    {
+        if(isInteger()) {
+            result = value.int_value();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a Json11Object instance.
+     *
+     * If the referenced Json11 value is an object, this function will return a
+     * std::optional containing a Json11Object instance referencing the
+     * object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<Json11Object> getObjectOptional() const
+    {
+        if (value.is_object()) {
+            return opt::make_optional(Json11Object(value));
+        }
+
+        return opt::optional<Json11Object>();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced Json11 value is an object, this function will
+     * retrieve the number of members in the object and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (value.is_object()) {
+            result = value.object_items().size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value.is_string()) {
+            result = value.string_value();
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return true;
+    }
+
+    bool isArray() const
+    {
+        return value.is_array();
+    }
+
+    bool isBool() const
+    {
+        return value.is_bool();
+    }
+
+    bool isDouble() const
+    {
+        return value.is_number();
+    }
+
+    bool isInteger() const
+    {
+        return value.is_number()
+            && value.int_value() == value.number_value();
+    }
+
+    bool isNull() const
+    {
+        return value.is_null();
+    }
+
+    bool isNumber() const
+    {
+        return value.is_number();
+    }
+
+    bool isObject() const
+    {
+        return value.is_object();
+    }
+
+    bool isString() const
+    {
+        return value.is_string();
+    }
+
+private:
+
+    /// Return a reference to an empty object singleton
+    static const json11::Json & emptyObject()
+    {
+        static const json11::Json object((json11::Json::object()));
+        return object;
+    }
+
+    /// Reference to the contained Json11 value.
+    const json11::Json &value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting Json11.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+class Json11Adapter:
+    public BasicAdapter<Json11Adapter,
+                        Json11Array,
+                        Json11ObjectMember,
+                        Json11Object,
+                        Json11Value>
+{
+public:
+
+    /// Construct a Json11Adapter that contains an empty object
+    Json11Adapter()
+      : BasicAdapter() { }
+
+    /// Construct a Json11Adapter containing a specific Json11 value
+    Json11Adapter(const json11::Json &value)
+      : BasicAdapter(value) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * Json11Adapter representing a value stored in the array. It has been
+ * implemented using the boost iterator_facade template.
+ *
+ * @see Json11Array
+ */
+class Json11ArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,  // bi-directional iterator
+        Json11Adapter>                    // value type
+{
+public:
+
+    /**
+     * @brief   Construct a new Json11ArrayValueIterator using an existing
+     *          Json11 iterator.
+     *
+     * @param   itr  Json11 iterator to store
+     */
+    Json11ArrayValueIterator(
+        const json11::Json::array::const_iterator &itr)
+      : itr(itr) { }
+
+    /// Returns a Json11Adapter that contains the value of the current
+    /// element.
+    Json11Adapter operator*() const
+    {
+        return Json11Adapter(*itr);
+    }
+
+    DerefProxy<Json11Adapter> operator->() const
+    {
+        return DerefProxy<Json11Adapter>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  iterator to compare against
+     *
+     * @returns true   if the iterators are equal, false otherwise.
+     */
+    bool operator==(const Json11ArrayValueIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const Json11ArrayValueIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const Json11ArrayValueIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    Json11ArrayValueIterator operator++(int)
+    {
+        Json11ArrayValueIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const Json11ArrayValueIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        itr += n;
+    }
+
+private:
+
+    json11::Json::array::const_iterator itr;
+};
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of Json11ObjectMember representing one of the members of the object. It
+ * has been implemented using the boost iterator_facade template.
+ *
+ * @see Json11Object
+ * @see Json11ObjectMember
+ */
+class Json11ObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,   // bi-directional iterator
+        Json11ObjectMember>                // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a Json11 iterator.
+     *
+     * @param   itr  Json11 iterator to store
+     */
+    Json11ObjectMemberIterator(
+        const json11::Json::object::const_iterator &itr)
+      : itr(itr) { }
+
+    /**
+     * @brief   Returns a Json11ObjectMember that contains the key and value
+     *          belonging to the object member identified by the iterator.
+     */
+    Json11ObjectMember operator*() const
+    {
+        return Json11ObjectMember(itr->first, itr->second);
+    }
+
+    DerefProxy<Json11ObjectMember> operator->() const
+    {
+        return DerefProxy<Json11ObjectMember>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const Json11ObjectMemberIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const Json11ObjectMemberIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const Json11ObjectMemberIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    Json11ObjectMemberIterator operator++(int)
+    {
+        Json11ObjectMemberIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const Json11ObjectMemberIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+private:
+
+    /// Iternal copy of the original Json11 iterator
+    json11::Json::object::const_iterator itr;
+};
+
+/// Specialisation of the AdapterTraits template struct for Json11Adapter.
+template<>
+struct AdapterTraits<valijson::adapters::Json11Adapter>
+{
+    typedef json11::Json DocumentType;
+
+    static std::string adapterName()
+    {
+        return "Json11Adapter";
+    }
+};
+
+inline bool Json11FrozenValue::equalTo(const Adapter &other, bool strict) const
+{
+    return Json11Adapter(value).equalTo(other, strict);
+}
+
+inline Json11ArrayValueIterator Json11Array::begin() const
+{
+    return value.array_items().begin();
+}
+
+inline Json11ArrayValueIterator Json11Array::end() const
+{
+    return value.array_items().end();
+}
+
+inline Json11ObjectMemberIterator Json11Object::begin() const
+{
+    return value.object_items().begin();
+}
+
+inline Json11ObjectMemberIterator Json11Object::end() const
+{
+    return value.object_items().end();
+}
+
+inline Json11ObjectMemberIterator Json11Object::find(
+    const std::string &propertyName) const
+{
+    return value.object_items().find(propertyName);
+}
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/jsoncpp_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/jsoncpp_adapter.hpp
new file mode 100644
index 0000000..4831f02
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/jsoncpp_adapter.hpp
@@ -0,0 +1,724 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the JsonCpp parser library.
+ *
+ * Include this file in your program to enable support for JsonCpp.
+ *
+ * This file defines the following classes (not in this order):
+ *  - JsonCppAdapter
+ *  - JsonCppArray
+ *  - JsonCppArrayValueIterator
+ *  - JsonCppFrozenValue
+ *  - JsonCppObject
+ *  - JsonCppObjectMember
+ *  - JsonCppObjectMemberIterator
+ *  - JsonCppValue
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is JsonCppAdapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_JSONCPP_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_JSONCPP_ADAPTER_HPP
+
+#include <stdint.h>
+#include <string>
+#include <iterator>
+
+#include <json/json.h>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+class JsonCppAdapter;
+class JsonCppArrayValueIterator;
+class JsonCppObjectMemberIterator;
+
+typedef std::pair<std::string, JsonCppAdapter> JsonCppObjectMember;
+
+/**
+ * @brief  Light weight wrapper for a JsonCpp array value.
+ *
+ * This class is light weight wrapper for a JsonCpp array. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * JsonCpp value, assumed to be an array, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class JsonCppArray
+{
+public:
+
+    typedef JsonCppArrayValueIterator const_iterator;
+    typedef JsonCppArrayValueIterator iterator;
+
+    /// Construct a JsonCppArray referencing an empty array.
+    JsonCppArray()
+      : value(emptyArray()) { }
+
+    /**
+     * @brief   Construct a JsonCppArray referencing a specific JsonCpp value.
+     *
+     * @param   value   reference to a JsonCpp value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an array.
+     */
+    JsonCppArray(const Json::Value &value)
+      : value(value)
+    {
+        if (!value.isArray()) {
+            throw std::runtime_error("Value is not an array.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for the first element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying JsonCpp implementation.
+     */
+    JsonCppArrayValueIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for one-past the last element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying JsonCpp implementation.
+     */
+    JsonCppArrayValueIterator end() const;
+
+    /// Return the number of elements in the array.
+    size_t size() const
+    {
+        return value.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a JsonCpp value that is an empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const Json::Value & emptyArray()
+    {
+        static const Json::Value array(Json::arrayValue);
+        return array;
+    }
+
+    /// Reference to the contained array
+    const Json::Value &value;
+
+};
+
+/**
+ * @brief  Light weight wrapper for a JsonCpp object.
+ *
+ * This class is light weight wrapper for a JsonCpp object. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * JsonCpp object, assumed to be an object, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class JsonCppObject
+{
+public:
+
+    typedef JsonCppObjectMemberIterator const_iterator;
+    typedef JsonCppObjectMemberIterator iterator;
+
+    /// Construct a JsonCppObject referencing an empty object singleton.
+    JsonCppObject()
+      : value(emptyObject()) { }
+
+    /**
+     * @brief   Construct a JsonCppObject referencing a specific JsonCpp value.
+     *
+     * @param   value  reference to a JsonCpp value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an object.
+     */
+    JsonCppObject(const Json::Value &value)
+      : value(value)
+    {
+        if (!value.isObject()) {
+            throw std::runtime_error("Value is not an object.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying JsonCpp implementation.
+     */
+    JsonCppObjectMemberIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying JsonCpp implementation.
+     */
+    JsonCppObjectMemberIterator end() const;
+
+    /**
+     * @brief   Return an iterator for a member/property with the given name
+     *
+     * @param   propertyName   Property name
+     *
+     * @returns a valid iterator if found, or an invalid iterator if not found
+     */
+    JsonCppObjectMemberIterator find(const std::string &propertyName) const;
+
+    /// Return the number of members in the object
+    size_t size() const
+    {
+        return value.size();
+    }
+
+private:
+
+    /// Return a reference to an empty JsonCpp object
+    static const Json::Value & emptyObject()
+    {
+        static const Json::Value object(Json::objectValue);
+        return object;
+    }
+
+    /// Reference to the contained object
+    const Json::Value &value;
+};
+
+/**
+ * @brief   Stores an independent copy of a JsonCpp value.
+ *
+ * This class allows a JsonCpp value to be stored independent of its original
+ * document. JsonCpp makes this easy to do, as it does not perform any
+ * custom memory management.
+ *
+ * @see FrozenValue
+ */
+class JsonCppFrozenValue: public FrozenValue
+{
+public:
+
+    /**
+     * @brief  Make a copy of a JsonCpp value
+     *
+     * @param  source  the JsonCpp value to be copied
+     */
+    explicit JsonCppFrozenValue(const Json::Value &source)
+      : value(source) { }
+
+    virtual FrozenValue * clone() const
+    {
+        return new JsonCppFrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /// Stored JsonCpp value
+    Json::Value value;
+};
+
+/**
+ * @brief   Light weight wrapper for a JsonCpp value.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a JsonCpp value. This class is responsible
+ * for the mechanics of actually reading a JsonCpp value, whereas the
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+class JsonCppValue
+{
+public:
+
+    /// Construct a wrapper for the empty object singleton
+    JsonCppValue()
+      : value(emptyObject()) { }
+
+    /// Construct a wrapper for a specific JsonCpp value
+    JsonCppValue(const Json::Value &value)
+      : value(value) { }
+
+    /**
+     * @brief   Create a new JsonCppFrozenValue instance that contains the
+     *          value referenced by this JsonCppValue instance.
+     *
+     * @returns pointer to a new JsonCppFrozenValue instance, belonging to the
+     *          caller.
+     */
+    FrozenValue * freeze() const
+    {
+        return new JsonCppFrozenValue(value);
+    }
+
+    /**
+     * @brief   Optionally return a JsonCppArray instance.
+     *
+     * If the referenced JsonCpp value is an array, this function will return a
+     * std::optional containing a JsonCppArray instance referencing the
+     * array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<JsonCppArray> getArrayOptional() const
+    {
+        if (value.isArray()) {
+            return opt::make_optional(JsonCppArray(value));
+        }
+
+        return opt::optional<JsonCppArray>();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced JsonCpp value is an array, this function will retrieve
+     * the number of elements in the array and store it in the output variable
+     * provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (value.isArray()) {
+            result = value.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &result) const
+    {
+        if (value.isBool()) {
+            result = value.asBool();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getDouble(double &result) const
+    {
+        if (value.isDouble()) {
+            result = value.asDouble();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getInteger(int64_t &result) const
+    {
+        if (value.isIntegral()) {
+            result = static_cast<int64_t>(value.asInt());
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a JsonCppObject instance.
+     *
+     * If the referenced JsonCpp value is an object, this function will return a
+     * std::optional containing a JsonCppObject instance referencing the
+     * object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<JsonCppObject> getObjectOptional() const
+    {
+        if (value.isObject()) {
+            return opt::make_optional(JsonCppObject(value));
+        }
+
+        return opt::optional<JsonCppObject>();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced JsonCpp value is an object, this function will retrieve
+     * the number of members in the object and store it in the output variable
+     * provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (value.isObject()) {
+            result = value.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value.isString()) {
+            result = value.asString();
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return true;
+    }
+
+    bool isArray() const
+    {
+        return value.isArray() && !value.isNull();
+    }
+
+    bool isBool() const
+    {
+        return value.isBool();
+    }
+
+    bool isDouble() const
+    {
+        return value.isDouble();
+    }
+
+    bool isInteger() const
+    {
+        return value.isIntegral() && !value.isBool();
+    }
+
+    bool isNull() const
+    {
+        return value.isNull();
+    }
+
+    bool isNumber() const
+    {
+        return value.isNumeric()  && !value.isBool();
+    }
+
+    bool isObject() const
+    {
+        return value.isObject() && !value.isNull();
+    }
+
+    bool isString() const
+    {
+        return value.isString();
+    }
+
+private:
+
+    /// Return a reference to an empty object singleton.
+    static const Json::Value &emptyObject()
+    {
+        static Json::Value object(Json::objectValue);
+        return object;
+    }
+
+    /// Reference to the contained JsonCpp value
+    const Json::Value &value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting JsonCpp.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+class JsonCppAdapter:
+    public BasicAdapter<JsonCppAdapter,
+                        JsonCppArray,
+                        JsonCppObjectMember,
+                        JsonCppObject,
+                        JsonCppValue>
+{
+public:
+
+    /// Construct a JsonCppAdapter that contains an empty object
+    JsonCppAdapter()
+      : BasicAdapter() { }
+
+    /// Construct a JsonCppAdapter containing a specific JsonCpp value
+    JsonCppAdapter(const Json::Value &value)
+      : BasicAdapter(value) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * JsonCppAdapter representing a value stored in the array. It has been
+ * implemented using the boost iterator_facade template.
+ *
+ * @see JsonCppArray
+ */
+class JsonCppArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,     // bi-directional iterator
+        JsonCppAdapter>                      // value type
+{
+
+public:
+
+    /**
+     * @brief   Construct a new JsonCppArrayValueIterator using an existing
+     *          JsonCpp iterator.
+     *
+     * @param   itr  JsonCpp iterator to store
+     */
+    JsonCppArrayValueIterator(const Json::Value::const_iterator &itr)
+      : itr(itr) { }
+
+    /// Returns a JsonCppAdapter that contains the value of the current element.
+    JsonCppAdapter operator*() const
+    {
+        return JsonCppAdapter(*itr);
+    }
+
+    DerefProxy<JsonCppAdapter> operator->() const
+    {
+        return DerefProxy<JsonCppAdapter>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   rhs  iterator to compare against
+     *
+     * @returns true if the iterators are equal, false otherwise.
+     */
+    bool operator==(const JsonCppArrayValueIterator &rhs) const
+    {
+        return itr == rhs.itr;
+    }
+
+    bool operator!=(const JsonCppArrayValueIterator &rhs) const
+    {
+        return !(itr == rhs.itr);
+    }
+
+    JsonCppArrayValueIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    JsonCppArrayValueIterator operator++(int)
+    {
+        JsonCppArrayValueIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    JsonCppArrayValueIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        if (n > 0) {
+            while (n-- > 0) {
+                itr++;
+            }
+        } else {
+            while (n++ < 0) {
+                itr--;
+            }
+        }
+    }
+
+private:
+
+    Json::Value::const_iterator itr;
+};
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of JsonCppObjectMember representing one of the members of the object. It has
+ * been implemented using the boost iterator_facade template.
+ *
+ * @see JsonCppObject
+ * @see JsonCppObjectMember
+ */
+class JsonCppObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,     // bi-directional iterator
+        JsonCppObjectMember>                 // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a JsonCpp iterator.
+     *
+     * @param   itr  JsonCpp iterator to store
+     */
+    JsonCppObjectMemberIterator(const Json::ValueConstIterator &itr)
+      : itr(itr) { }
+
+    /**
+     * @brief   Returns a JsonCppObjectMember that contains the key and value
+     *          belonging to the object member identified by the iterator.
+     */
+    JsonCppObjectMember operator*() const
+    {
+        return JsonCppObjectMember(itr.key().asString(), *itr);
+    }
+
+    DerefProxy<JsonCppObjectMember> operator->() const
+    {
+        return DerefProxy<JsonCppObjectMember>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   rhs  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const JsonCppObjectMemberIterator &rhs) const
+    {
+        return itr == rhs.itr;
+    }
+
+    bool operator!=(const JsonCppObjectMemberIterator &rhs) const
+    {
+        return !(itr == rhs.itr);
+    }
+
+    const JsonCppObjectMemberIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    JsonCppObjectMemberIterator operator++(int)
+    {
+        JsonCppObjectMemberIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    JsonCppObjectMemberIterator operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+private:
+
+    /// Iternal copy of the original JsonCpp iterator
+    Json::ValueConstIterator itr;
+};
+
+/// Specialisation of the AdapterTraits template struct for JsonCppAdapter.
+template<>
+struct AdapterTraits<valijson::adapters::JsonCppAdapter>
+{
+    typedef Json::Value DocumentType;
+
+    static std::string adapterName()
+    {
+        return "JsonCppAdapter";
+    }
+};
+
+inline bool JsonCppFrozenValue::equalTo(const Adapter &other, bool strict) const
+{
+    return JsonCppAdapter(value).equalTo(other, strict);
+}
+
+inline JsonCppArrayValueIterator JsonCppArray::begin() const
+{
+    return value.begin();
+}
+
+inline JsonCppArrayValueIterator JsonCppArray::end() const
+{
+    return value.end();
+}
+
+inline JsonCppObjectMemberIterator JsonCppObject::begin() const
+{
+    return value.begin();
+}
+
+inline JsonCppObjectMemberIterator JsonCppObject::end() const
+{
+    return value.end();
+}
+
+inline JsonCppObjectMemberIterator JsonCppObject::find(
+    const std::string &propertyName) const
+{
+    if (value.isMember(propertyName)) {
+        Json::ValueConstIterator itr;
+        for ( itr = value.begin(); itr != value.end(); ++itr) {
+            if (itr.key() == propertyName) {
+                return itr;
+            }
+        }
+    }
+
+    return value.end();
+}
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp
new file mode 100644
index 0000000..f77a2bf
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp
@@ -0,0 +1,712 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the nlohmann json parser library.
+ *
+ * Include this file in your program to enable support for nlohmann json.
+ *
+ * This file defines the following classes (not in this order):
+ *  - NlohmannJsonAdapter
+ *  - NlohmannJsonArray
+ *  - NlohmannJsonValueIterator
+ *  - NlohmannJsonFrozenValue
+ *  - NlohmannJsonObject
+ *  - NlohmannJsonObjectMember
+ *  - NlohmannJsonObjectMemberIterator
+ *  - NlohmannJsonValue
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is NlohmannJsonAdapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_NLOHMANN_JSON_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_NLOHMANN_JSON_ADAPTER_HPP
+
+#include <string>
+#include <json.hpp>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+class NlohmannJsonAdapter;
+class NlohmannJsonArrayValueIterator;
+class NlohmannJsonObjectMemberIterator;
+
+typedef std::pair<std::string, NlohmannJsonAdapter> NlohmannJsonObjectMember;
+
+/**
+ * @brief  Light weight wrapper for a NlohmannJson array value.
+ *
+ * This class is light weight wrapper for a NlohmannJson array. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * NlohmannJson value, assumed to be an array, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class NlohmannJsonArray
+{
+public:
+
+    typedef NlohmannJsonArrayValueIterator const_iterator;
+    typedef NlohmannJsonArrayValueIterator iterator;
+
+    /// Construct a NlohmannJsonArray referencing an empty array.
+    NlohmannJsonArray()
+      : value(emptyArray()) { }
+
+    /**
+     * @brief   Construct a NlohmannJsonArray referencing a specific NlohmannJson
+     *          value.
+     *
+     * @param   value   reference to a NlohmannJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an array.
+     */
+    NlohmannJsonArray(const nlohmann::json &value)
+      : value(value)
+    {
+        if (!value.is_array()) {
+            throw std::runtime_error("Value is not an array.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for the first element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying NlohmannJson implementation.
+     */
+    NlohmannJsonArrayValueIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for one-past the last element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying NlohmannJson implementation.
+     */
+    NlohmannJsonArrayValueIterator end() const;
+
+    /// Return the number of elements in the array
+    size_t size() const
+    {
+        return value.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a NlohmannJson value that is an empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const nlohmann::json & emptyArray()
+    {
+        static const nlohmann::json array = nlohmann::json::array();
+        return array;
+    }
+
+    /// Reference to the contained value
+    const nlohmann::json &value;
+};
+
+/**
+ * @brief  Light weight wrapper for a NlohmannJson object.
+ *
+ * This class is light weight wrapper for a NlohmannJson object. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * NlohmannJson value, assumed to be an object, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class NlohmannJsonObject
+{
+public:
+
+    typedef NlohmannJsonObjectMemberIterator const_iterator;
+    typedef NlohmannJsonObjectMemberIterator iterator;
+
+    /// Construct a NlohmannJsonObject referencing an empty object singleton.
+    NlohmannJsonObject()
+      : value(emptyObject()) { }
+
+    /**
+     * @brief   Construct a NlohmannJsonObject referencing a specific NlohmannJson
+     *          value.
+     *
+     * @param   value  reference to a NlohmannJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an object.
+     */
+    NlohmannJsonObject(const nlohmann::json &value)
+      : value(value)
+    {
+        if (!value.is_object()) {
+            throw std::runtime_error("Value is not an object.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying NlohmannJson implementation.
+     */
+    NlohmannJsonObjectMemberIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying NlohmannJson implementation.
+     */
+    NlohmannJsonObjectMemberIterator end() const;
+
+    /**
+     * @brief   Return an iterator for the object member with the specified
+     *          property name.
+     *
+     * If an object member with the specified name does not exist, the iterator
+     * returned will be the same as the iterator returned by the end() function.
+     *
+     * @param   propertyName  property name to search for
+     */
+    NlohmannJsonObjectMemberIterator find(const std::string &propertyName) const;
+
+    /// Returns the number of members belonging to this object.
+    size_t size() const
+    {
+        return value.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a NlohmannJson value that is empty object.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const nlohmann::json & emptyObject()
+    {
+        static const nlohmann::json object = nlohmann::json::object();
+        return object;
+    }
+
+    /// Reference to the contained object
+    const nlohmann::json &value;
+};
+
+
+/**
+ * @brief   Stores an independent copy of a NlohmannJson value.
+ *
+ * This class allows a NlohmannJson value to be stored independent of its original
+ * document. NlohmannJson makes this easy to do, as it does not perform any
+ * custom memory management.
+ *
+ * @see FrozenValue
+ */
+class NlohmannJsonFrozenValue: public FrozenValue
+{
+public:
+
+    /**
+     * @brief  Make a copy of a NlohmannJson value
+     *
+     * @param  source  the NlohmannJson value to be copied
+     */
+    explicit NlohmannJsonFrozenValue(const nlohmann::json &source)
+      : value(source) { }
+
+    virtual FrozenValue * clone() const
+    {
+        return new NlohmannJsonFrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /// Stored NlohmannJson value
+    nlohmann::json value;
+};
+
+
+/**
+ * @brief   Light weight wrapper for a NlohmannJson value.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a NlohmannJson value. This class is responsible
+ * for the mechanics of actually reading a NlohmannJson value, whereas the
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+class NlohmannJsonValue
+{
+public:
+
+    /// Construct a wrapper for the empty object singleton
+    NlohmannJsonValue()
+      : value(emptyObject()) { }
+
+    /// Construct a wrapper for a specific NlohmannJson value
+    NlohmannJsonValue(const nlohmann::json &value)
+      : value(value) { }
+
+    /**
+     * @brief   Create a new NlohmannJsonFrozenValue instance that contains the
+     *          value referenced by this NlohmannJsonValue instance.
+     *
+     * @returns pointer to a new NlohmannJsonFrozenValue instance, belonging to the
+     *          caller.
+     */
+    FrozenValue * freeze() const
+    {
+        return new NlohmannJsonFrozenValue(value);
+    }
+
+    /**
+     * @brief   Optionally return a NlohmannJsonArray instance.
+     *
+     * If the referenced NlohmannJson value is an array, this function will return
+     * a std::optional containing a NlohmannJsonArray instance referencing the
+     * array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<NlohmannJsonArray> getArrayOptional() const
+    {
+        if (value.is_array()) {
+            return opt::make_optional(NlohmannJsonArray(value));
+        }
+
+        return opt::optional<NlohmannJsonArray>();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced NlohmannJson value is an array, this function will
+     * retrieve the number of elements in the array and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (value.is_array()) {
+            result = value.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &result) const
+    {
+        if (value.is_boolean()) {
+            result = value.get<bool>();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getDouble(double &result) const
+    {
+        if (value.is_number_float()) {
+            result = value.get<double>();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getInteger(int64_t &result) const
+    {
+        if(value.is_number_integer()) {
+            result = value.get<int64_t>();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a NlohmannJsonObject instance.
+     *
+     * If the referenced NlohmannJson value is an object, this function will return a
+     * std::optional containing a NlohmannJsonObject instance referencing the
+     * object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<NlohmannJsonObject> getObjectOptional() const
+    {
+        if (value.is_object()) {
+            return opt::make_optional(NlohmannJsonObject(value));
+        }
+
+        return opt::optional<NlohmannJsonObject>();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced NlohmannJson value is an object, this function will
+     * retrieve the number of members in the object and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (value.is_object()) {
+            result = value.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value.is_string()) {
+            result = value.get<std::string>();
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return true;
+    }
+
+    bool isArray() const
+    {
+        return value.is_array();
+    }
+
+    bool isBool() const
+    {
+        return value.is_boolean();
+    }
+
+    bool isDouble() const
+    {
+        return value.is_number_float();
+    }
+
+    bool isInteger() const
+    {
+        return value.is_number_integer();
+    }
+
+    bool isNull() const
+    {
+        return value.is_null();
+    }
+
+    bool isNumber() const
+    {
+        return value.is_number();
+    }
+
+    bool isObject() const
+    {
+        return value.is_object();
+    }
+
+    bool isString() const
+    {
+        return value.is_string();
+    }
+
+private:
+
+    /// Return a reference to an empty object singleton
+    static const nlohmann::json & emptyObject()
+    {
+        static const nlohmann::json object = nlohmann::json::object();
+        return object;
+    }
+
+    /// Reference to the contained NlohmannJson value.
+    const nlohmann::json &value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting NlohmannJson.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+class NlohmannJsonAdapter:
+    public BasicAdapter<NlohmannJsonAdapter,
+        NlohmannJsonArray,
+        NlohmannJsonObjectMember,
+        NlohmannJsonObject,
+        NlohmannJsonValue>
+{
+public:
+    /// Construct a NlohmannJsonAdapter that contains an empty object
+    NlohmannJsonAdapter()
+      : BasicAdapter() { }
+
+    /// Construct a NlohmannJsonAdapter containing a specific Nlohmann Json object
+    NlohmannJsonAdapter(const nlohmann::json &value)
+      : BasicAdapter(NlohmannJsonValue{value}) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * NlohmannJsonAdapter representing a value stored in the array. It has been
+ * implemented using the boost iterator_facade template.
+ *
+ * @see NlohmannJsonArray
+ */
+class NlohmannJsonArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,  // bi-directional iterator
+        NlohmannJsonAdapter>                 // value type
+{
+public:
+
+    /**
+     * @brief   Construct a new NlohmannJsonArrayValueIterator using an existing
+     *          NlohmannJson iterator.
+     *
+     * @param   itr  NlohmannJson iterator to store
+     */
+    NlohmannJsonArrayValueIterator(const nlohmann::json::const_iterator &itr)
+      : itr(itr) { }
+
+    /// Returns a NlohmannJsonAdapter that contains the value of the current
+    /// element.
+    NlohmannJsonAdapter operator*() const
+    {
+        return NlohmannJsonAdapter(*itr);
+    }
+
+    DerefProxy<NlohmannJsonAdapter> operator->() const
+    {
+        return DerefProxy<NlohmannJsonAdapter>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  iterator to compare against
+     *
+     * @returns true   if the iterators are equal, false otherwise.
+     */
+    bool operator==(const NlohmannJsonArrayValueIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const NlohmannJsonArrayValueIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const NlohmannJsonArrayValueIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    NlohmannJsonArrayValueIterator operator++(int)
+    {
+        NlohmannJsonArrayValueIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const NlohmannJsonArrayValueIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        itr += n;
+    }
+
+private:
+    nlohmann::json::const_iterator itr;
+};
+
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of NlohmannJsonObjectMember representing one of the members of the object. It
+ * has been implemented using the boost iterator_facade template.
+ *
+ * @see NlohmannJsonObject
+ * @see NlohmannJsonObjectMember
+ */
+class NlohmannJsonObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,     // bi-directional iterator
+        NlohmannJsonObjectMember>            // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a NlohmannJson iterator.
+     *
+     * @param   itr  NlohmannJson iterator to store
+     */
+    NlohmannJsonObjectMemberIterator(const nlohmann::json::const_iterator &itr)
+      : itr(itr) { }
+
+    /**
+     * @brief   Returns a NlohmannJsonObjectMember that contains the key and value
+     *          belonging to the object member identified by the iterator.
+     */
+    NlohmannJsonObjectMember operator*() const
+    {
+        return NlohmannJsonObjectMember(itr.key(), itr.value());
+    }
+
+    DerefProxy<NlohmannJsonObjectMember> operator->() const
+    {
+        return DerefProxy<NlohmannJsonObjectMember>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const NlohmannJsonObjectMemberIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const NlohmannJsonObjectMemberIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const NlohmannJsonObjectMemberIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    NlohmannJsonObjectMemberIterator operator++(int)
+    {
+        NlohmannJsonObjectMemberIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const NlohmannJsonObjectMemberIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+private:
+
+    /// Iternal copy of the original NlohmannJson iterator
+    nlohmann::json::const_iterator itr;
+};
+
+/// Specialisation of the AdapterTraits template struct for NlohmannJsonAdapter.
+template<>
+struct AdapterTraits<valijson::adapters::NlohmannJsonAdapter>
+{
+    typedef nlohmann::json DocumentType;
+
+    static std::string adapterName()
+    {
+        return "NlohmannJsonAdapter";
+    }
+};
+
+inline bool NlohmannJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
+{
+    return NlohmannJsonAdapter(value).equalTo(other, strict);
+}
+
+inline NlohmannJsonArrayValueIterator NlohmannJsonArray::begin() const
+{
+    return value.begin();
+}
+
+inline NlohmannJsonArrayValueIterator NlohmannJsonArray::end() const
+{
+    return value.end();
+}
+
+inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::begin() const
+{
+    return value.begin();
+}
+
+inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::end() const
+{
+    return value.end();
+}
+
+inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::find(
+        const std::string &propertyName) const
+{
+    return value.find(propertyName);
+}
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
+
diff --git a/examples/validator/valijson/include/valijson/adapters/picojson_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/picojson_adapter.hpp
new file mode 100644
index 0000000..b6d17c9
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/picojson_adapter.hpp
@@ -0,0 +1,727 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the PicoJson parser library.
+ *
+ * Include this file in your program to enable support for PicoJson.
+ *
+ * This file defines the following classes (not in this order):
+ *  - PicoJsonAdapter
+ *  - PicoJsonArray
+ *  - PicoJsonArrayValueIterator
+ *  - PicoJsonFrozenValue
+ *  - PicoJsonObject
+ *  - PicoJsonObjectMember
+ *  - PicoJsonObjectMemberIterator
+ *  - PicoJsonValue
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is PicoJsonAdapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_PICOJSON_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_PICOJSON_ADAPTER_HPP
+
+#include <string>
+
+#include <picojson.h>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+class PicoJsonAdapter;
+class PicoJsonArrayValueIterator;
+class PicoJsonObjectMemberIterator;
+
+typedef std::pair<std::string, PicoJsonAdapter> PicoJsonObjectMember;
+
+/**
+ * @brief  Light weight wrapper for a PicoJson array value.
+ *
+ * This class is light weight wrapper for a PicoJson array. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * PicoJson value, assumed to be an array, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class PicoJsonArray
+{
+public:
+
+    typedef PicoJsonArrayValueIterator const_iterator;
+    typedef PicoJsonArrayValueIterator iterator;
+
+    /// Construct a PicoJsonArray referencing an empty array.
+    PicoJsonArray()
+      : value(emptyArray()) { }
+
+    /**
+     * @brief   Construct a PicoJsonArray referencing a specific PicoJson
+     *          value.
+     *
+     * @param   value   reference to a PicoJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an array.
+     */
+    explicit PicoJsonArray(const picojson::value &value)
+      : value(value)
+    {
+        if (!value.is<picojson::array>()) {
+            throw std::runtime_error("Value is not an array.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for the first element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying PicoJson implementation.
+     */
+    PicoJsonArrayValueIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for one-past the last element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying PicoJson implementation.
+     */
+    PicoJsonArrayValueIterator end() const;
+
+    /// Return the number of elements in the array
+    size_t size() const
+    {
+        const picojson::array &array = value.get<picojson::array>();
+        return array.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a PicoJson value that is an empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const picojson::value & emptyArray()
+    {
+        static const picojson::value array(picojson::array_type, false);
+        return array;
+    }
+
+    /// Reference to the contained value
+    const picojson::value &value;
+};
+
+/**
+ * @brief  Light weight wrapper for a PicoJson object.
+ *
+ * This class is light weight wrapper for a PicoJson object. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * PicoJson value, assumed to be an object, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class PicoJsonObject
+{
+public:
+
+    typedef PicoJsonObjectMemberIterator const_iterator;
+    typedef PicoJsonObjectMemberIterator iterator;
+
+    /// Construct a PicoJsonObject referencing an empty object singleton.
+    PicoJsonObject()
+      : value(emptyObject()) { }
+
+    /**
+     * @brief   Construct a PicoJsonObject referencing a specific PicoJson
+     *          value.
+     *
+     * @param   value  reference to a PicoJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an object.
+     */
+    PicoJsonObject(const picojson::value &value)
+      : value(value)
+    {
+        if (!value.is<picojson::object>()) {
+            throw std::runtime_error("Value is not an object.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying PicoJson implementation.
+     */
+    PicoJsonObjectMemberIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying PicoJson implementation.
+     */
+    PicoJsonObjectMemberIterator end() const;
+
+    /**
+     * @brief   Return an iterator for the object member with the specified
+     *          property name.
+     *
+     * If an object member with the specified name does not exist, the iterator
+     * returned will be the same as the iterator returned by the end() function.
+     *
+     * @param   propertyName  property name to search for
+     */
+    PicoJsonObjectMemberIterator find(const std::string &propertyName) const;
+
+    /// Returns the number of members belonging to this object.
+    size_t size() const
+    {
+        const picojson::object &object = value.get<picojson::object>();
+        return object.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a PicoJson value that is empty object.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const picojson::value & emptyObject()
+    {
+        static const picojson::value object(picojson::object_type, false);
+        return object;
+    }
+
+    /// Reference to the contained object
+    const picojson::value &value;
+};
+
+/**
+ * @brief   Stores an independent copy of a PicoJson value.
+ *
+ * This class allows a PicoJson value to be stored independent of its original
+ * document. PicoJson makes this easy to do, as it does not perform any
+ * custom memory management.
+ *
+ * @see FrozenValue
+ */
+class PicoJsonFrozenValue: public FrozenValue
+{
+public:
+
+    /**
+     * @brief  Make a copy of a PicoJson value
+     *
+     * @param  source  the PicoJson value to be copied
+     */
+    explicit PicoJsonFrozenValue(const picojson::value &source)
+      : value(source) { }
+
+    virtual FrozenValue * clone() const
+    {
+        return new PicoJsonFrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /// Stored PicoJson value
+    picojson::value value;
+};
+
+/**
+ * @brief   Light weight wrapper for a PicoJson value.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a PicoJson value. This class is responsible
+ * for the mechanics of actually reading a PicoJson value, whereas the
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+class PicoJsonValue
+{
+public:
+
+    /// Construct a wrapper for the empty object singleton
+    PicoJsonValue()
+      : value(emptyObject()) { }
+
+    /// Construct a wrapper for a specific PicoJson value
+    PicoJsonValue(const picojson::value &value)
+      : value(value) { }
+
+    /**
+     * @brief   Create a new PicoJsonFrozenValue instance that contains the
+     *          value referenced by this PicoJsonValue instance.
+     *
+     * @returns pointer to a new PicoJsonFrozenValue instance, belonging to the
+     *          caller.
+     */
+    FrozenValue * freeze() const
+    {
+        return new PicoJsonFrozenValue(value);
+    }
+
+    /**
+     * @brief   Optionally return a PicoJsonArray instance.
+     *
+     * If the referenced PicoJson value is an array, this function will return
+     * a std::optional containing a PicoJsonArray instance referencing the
+     * array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<PicoJsonArray> getArrayOptional() const
+    {
+        if (value.is<picojson::array>()) {
+            return opt::make_optional(PicoJsonArray(value));
+        }
+
+        return opt::optional<PicoJsonArray>();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced PicoJson value is an array, this function will
+     * retrieve the number of elements in the array and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (value.is<picojson::array>()) {
+            const picojson::array& array = value.get<picojson::array>();
+            result = array.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &result) const
+    {
+        if (value.is<bool>()) {
+            result = value.get<bool>();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getDouble(double &result) const
+    {
+        if (value.is<double>()) {
+            result = value.get<double>();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getInteger(int64_t &result) const
+    {
+        if (value.is<int64_t>()) {
+            result = value.get<int64_t>();
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a PicoJsonObject instance.
+     *
+     * If the referenced PicoJson value is an object, this function will return a
+     * std::optional containing a PicoJsonObject instance referencing the
+     * object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<PicoJsonObject> getObjectOptional() const
+    {
+        if (value.is<picojson::object>()) {
+            return opt::make_optional(PicoJsonObject(value));
+        }
+
+        return opt::optional<PicoJsonObject>();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced PicoJson value is an object, this function will
+     * retrieve the number of members in the object and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (value.is<picojson::object>()) {
+            const picojson::object &object = value.get<picojson::object>();
+            result = object.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value.is<std::string>()) {
+            result = value.get<std::string>();
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return true;
+    }
+
+    bool isArray() const
+    {
+        return value.is<picojson::array>();
+    }
+
+    bool isBool() const
+    {
+        return value.is<bool>();
+    }
+
+    bool isDouble() const
+    {
+        if (value.is<int64_t>()) {
+            return false;
+        }
+
+        return value.is<double>();
+    }
+
+    bool isInteger() const
+    {
+        return value.is<int64_t>();
+    }
+
+    bool isNull() const
+    {
+        return value.is<picojson::null>();
+    }
+
+    bool isNumber() const
+    {
+        return value.is<double>();
+    }
+
+    bool isObject() const
+    {
+        return value.is<picojson::object>();
+    }
+
+    bool isString() const
+    {
+        return value.is<std::string>();
+    }
+
+private:
+
+    /// Return a reference to an empty object singleton
+    static const picojson::value & emptyObject()
+    {
+        static const picojson::value object(picojson::object_type, false);
+        return object;
+    }
+
+    /// Reference to the contained PicoJson value.
+    const picojson::value &value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting PicoJson.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+class PicoJsonAdapter:
+    public BasicAdapter<PicoJsonAdapter,
+                        PicoJsonArray,
+                        PicoJsonObjectMember,
+                        PicoJsonObject,
+                        PicoJsonValue>
+{
+public:
+
+    /// Construct a PicoJsonAdapter that contains an empty object
+    PicoJsonAdapter()
+      : BasicAdapter() { }
+
+    /// Construct a PicoJsonAdapter containing a specific PicoJson value
+    PicoJsonAdapter(const picojson::value &value)
+      : BasicAdapter(value) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * PicoJsonAdapter representing a value stored in the array. It has been
+ * implemented using the std::iterator template.
+ *
+ * @see PicoJsonArray
+ */
+class PicoJsonArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,     // bi-directional iterator
+        PicoJsonAdapter>                     // value type
+{
+public:
+
+    /**
+     * @brief   Construct a new PicoJsonArrayValueIterator using an existing
+     *          PicoJson iterator.
+     *
+     * @param   itr  PicoJson iterator to store
+     */
+    PicoJsonArrayValueIterator(
+        const picojson::array::const_iterator &itr)
+      : itr(itr) { }
+
+    /// Returns a PicoJsonAdapter that contains the value of the current
+    /// element.
+    PicoJsonAdapter operator*() const
+    {
+        return PicoJsonAdapter(*itr);
+    }
+
+    DerefProxy<PicoJsonAdapter> operator->() const
+    {
+        return DerefProxy<PicoJsonAdapter>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  iterator to compare against
+     *
+     * @returns true   if the iterators are equal, false otherwise.
+     */
+    bool operator==(const PicoJsonArrayValueIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const PicoJsonArrayValueIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const PicoJsonArrayValueIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    PicoJsonArrayValueIterator operator++(int)
+    {
+        PicoJsonArrayValueIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const PicoJsonArrayValueIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        itr += n;
+    }
+
+private:
+
+    picojson::array::const_iterator itr;
+};
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of PicoJsonObjectMember representing one of the members of the object. It
+ * has been implemented using the boost iterator_facade template.
+ *
+ * @see PicoJsonObject
+ * @see PicoJsonObjectMember
+ */
+class PicoJsonObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,  // bi-directional iterator
+        PicoJsonObjectMember>             // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a PicoJson iterator.
+     *
+     * @param   itr  PicoJson iterator to store
+     */
+    PicoJsonObjectMemberIterator(
+        const picojson::object::const_iterator &itr)
+      : itr(itr) { }
+
+    /**
+     * @brief   Returns a PicoJsonObjectMember that contains the key and value
+     *          belonging to the object member identified by the iterator.
+     */
+    PicoJsonObjectMember operator*() const
+    {
+        return PicoJsonObjectMember(itr->first, itr->second);
+    }
+
+    DerefProxy<PicoJsonObjectMember> operator->() const
+    {
+        return DerefProxy<PicoJsonObjectMember>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const PicoJsonObjectMemberIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const PicoJsonObjectMemberIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const PicoJsonObjectMemberIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    PicoJsonObjectMemberIterator operator++(int)
+    {
+        PicoJsonObjectMemberIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const PicoJsonObjectMemberIterator& operator--(int)
+    {
+        itr--;
+
+        return *this;
+    }
+
+private:
+
+    /// Iternal copy of the original PicoJson iterator
+    picojson::object::const_iterator itr;
+};
+
+/// Specialisation of the AdapterTraits template struct for PicoJsonAdapter.
+template<>
+struct AdapterTraits<valijson::adapters::PicoJsonAdapter>
+{
+    typedef picojson::value DocumentType;
+
+    static std::string adapterName()
+    {
+        return "PicoJsonAdapter";
+    }
+};
+
+inline bool PicoJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
+{
+    return PicoJsonAdapter(value).equalTo(other, strict);
+}
+
+inline PicoJsonArrayValueIterator PicoJsonArray::begin() const
+{
+    const picojson::array &array = value.get<picojson::array>();
+    return array.begin();
+}
+
+inline PicoJsonArrayValueIterator PicoJsonArray::end() const
+{
+    const picojson::array &array = value.get<picojson::array>();
+    return array.end();
+}
+
+inline PicoJsonObjectMemberIterator PicoJsonObject::begin() const
+{
+    const picojson::object &object = value.get<picojson::object>();
+    return object.begin();
+}
+
+inline PicoJsonObjectMemberIterator PicoJsonObject::end() const
+{
+    const picojson::object &object = value.get<picojson::object>();
+    return object.end();
+}
+
+inline PicoJsonObjectMemberIterator PicoJsonObject::find(
+    const std::string &propertyName) const
+{
+    const picojson::object &object = value.get<picojson::object>();
+    return object.find(propertyName);
+}
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/poco_json_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/poco_json_adapter.hpp
new file mode 100644
index 0000000..915befc
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/poco_json_adapter.hpp
@@ -0,0 +1,728 @@
+/**
+* @file
+*
+* @brief   Adapter implementation for the Poco json parser library.
+*
+* Include this file in your program to enable support for Poco json.
+*
+* This file defines the following classes (not in this order):
+*  - PocoJsonAdapter
+*  - PocoJsonArray
+*  - PocoJsonValueIterator
+*  - PocoJsonFrozenValue
+*  - PocoJsonObject
+*  - PocoJsonObjectMember
+*  - PocoJsonObjectMemberIterator
+*  - PocoJsonValue
+*
+* Due to the dependencies that exist between these classes, the ordering of
+* class declarations and definitions may be a bit confusing. The best place to
+* start is PocoJsonAdapter. This class definition is actually very small,
+* since most of the functionality is inherited from the BasicAdapter class.
+* Most of the classes in this file are provided as template arguments to the
+* inherited BasicAdapter class.
+*/
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_POCO_JSON_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_POCO_JSON_ADAPTER_HPP
+
+#include <string>
+#include <Poco/JSON/Object.h>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson
+{
+    namespace adapters
+    {
+
+        class PocoJsonAdapter;
+        class PocoJsonArrayValueIterator;
+        class PocoJsonObjectMemberIterator;
+
+        typedef std::pair<std::string, PocoJsonAdapter> PocoJsonObjectMember;
+
+        /**
+        * @brief  Light weight wrapper for a PocoJson array value.
+        *
+        * This class is light weight wrapper for a PocoJson array. It provides a
+        * minimum set of container functions and typedefs that allow it to be used as
+        * an iterable container.
+        *
+        * An instance of this class contains a single reference to the underlying
+        * PocoJson value, assumed to be an array, so there is very little overhead
+        * associated with copy construction and passing by value.
+        */
+        class PocoJsonArray
+        {
+        public:
+
+            typedef PocoJsonArrayValueIterator const_iterator;
+            typedef PocoJsonArrayValueIterator iterator;
+
+            /// Construct a PocoJsonArray referencing an empty array.
+            PocoJsonArray()
+                : value(emptyArray())
+            { }
+
+            /**
+            * @brief   Construct a PocoJsonArray referencing a specific PocoJson
+            *          value.
+            *
+            * @param   value   reference to a PocoJson value
+            *
+            * Note that this constructor will throw an exception if the value is not
+            * an array.
+            */
+            PocoJsonArray(const Poco::Dynamic::Var &value)
+                : value(value)
+            {
+                if (value.type() != typeid(Poco::JSON::Array::Ptr)) {
+                    throw std::runtime_error("Value is not an array.");
+                }
+            }
+
+            /**
+            * @brief   Return an iterator for the first element of the array.
+            *
+            * The iterator return by this function is effectively the iterator
+            * returned by the underlying PocoJson implementation.
+            */
+            PocoJsonArrayValueIterator begin() const;
+
+            /**
+            * @brief   Return an iterator for one-past the last element of the array.
+            *
+            * The iterator return by this function is effectively the iterator
+            * returned by the underlying PocoJson implementation.
+            */
+            PocoJsonArrayValueIterator end() const;
+
+            /// Return the number of elements in the array
+            size_t size() const
+            {
+                return value.extract<Poco::JSON::Array::Ptr>()->size();
+            }
+
+        private:
+
+            /**
+            * @brief   Return a PocoJson value that is an empty array.
+            */
+            static Poco::Dynamic::Var emptyArray()
+            {
+                Poco::Dynamic::Var array = Poco::JSON::Array::Ptr();
+                return array;
+            }
+
+            /// Contained value
+            Poco::Dynamic::Var value;
+        };
+
+        /**
+        * @brief  Light weight wrapper for a PocoJson object.
+        *
+        * This class is light weight wrapper for a PocoJson object. It provides a
+        * minimum set of container functions and typedefs that allow it to be used as
+        * an iterable container.
+        *
+        * An instance of this class contains a single reference to the underlying
+        * PocoJson value, assumed to be an object, so there is very little overhead
+        * associated with copy construction and passing by value.
+        */
+        class PocoJsonObject
+        {
+        public:
+
+            typedef PocoJsonObjectMemberIterator const_iterator;
+            typedef PocoJsonObjectMemberIterator iterator;
+
+            /// Construct a PocoJsonObject an empty object.
+            PocoJsonObject()
+                : value(emptyObject())
+            { }
+
+            /**
+            * @brief   Construct a PocoJsonObject referencing a specific PocoJson
+            *          value.
+            *
+            * @param   value  reference to a PocoJson value
+            *
+            * Note that this constructor will throw an exception if the value is not
+            * an object.
+            */
+            PocoJsonObject(const Poco::Dynamic::Var &value)
+                : value(value)
+            {
+                if (value.type() != typeid(Poco::JSON::Object::Ptr)) {
+                    throw std::runtime_error("Value is not an object.");
+                }
+            }
+
+            /**
+            * @brief   Return an iterator for this first object member
+            *
+            * The iterator return by this function is effectively a wrapper around
+            * the iterator value returned by the underlying PocoJson implementation.
+            */
+            PocoJsonObjectMemberIterator begin() const;
+
+            /**
+            * @brief   Return an iterator for an invalid object member that indicates
+            *          the end of the collection.
+            *
+            * The iterator return by this function is effectively a wrapper around
+            * the iterator value returned by the underlying PocoJson implementation.
+            */
+            PocoJsonObjectMemberIterator end() const;
+
+            /**
+            * @brief   Return an iterator for the object member with the specified
+            *          property name.
+            *
+            * If an object member with the specified name does not exist, the iterator
+            * returned will be the same as the iterator returned by the end() function.
+            *
+            * @param   propertyName  property name to search for
+            */
+            PocoJsonObjectMemberIterator find(const std::string &propertyName) const;
+
+            /// Returns the number of members belonging to this object.
+            size_t size() const
+            {
+                return value.extract<Poco::JSON::Object::Ptr>()->size();
+            }
+
+        private:
+
+            /**
+            * @brief   Return a PocoJson value that is empty object.
+            */
+            static Poco::Dynamic::Var emptyObject()
+            {
+                Poco::Dynamic::Var object = Poco::JSON::Object::Ptr();
+                return object;
+            }
+
+            /// Contained value
+            Poco::Dynamic::Var value;
+        };
+
+        /**
+        * @brief   Stores an independent copy of a PocoJson value.
+        *
+        * This class allows a PocoJson value to be stored independent of its original
+        * document. PocoJson makes this easy to do, as it does not perform any
+        * custom memory management.
+        *
+        * @see FrozenValue
+        */
+        class PocoJsonFrozenValue : public FrozenValue
+        {
+        public:
+
+            /**
+            * @brief  Make a copy of a PocoJson value
+            *
+            * @param  source  the PocoJson value to be copied
+            */
+            explicit PocoJsonFrozenValue(const Poco::Dynamic::Var &source)
+                : value(source)
+            { }
+
+            virtual FrozenValue * clone() const
+            {
+                return new PocoJsonFrozenValue(value);
+            }
+
+            virtual bool equalTo(const Adapter &other, bool strict) const;
+
+        private:
+
+            /// Stored PocoJson value
+            Poco::Dynamic::Var value;
+        };
+
+
+        /**
+        * @brief   Light weight wrapper for a PocoJson value.
+        *
+        * This class is passed as an argument to the BasicAdapter template class,
+        * and is used to provide access to a PocoJson value. This class is responsible
+        * for the mechanics of actually reading a PocoJson value, whereas the
+        * BasicAdapter class is responsible for the semantics of type comparisons
+        * and conversions.
+        *
+        * The functions that need to be provided by this class are defined implicitly
+        * by the implementation of the BasicAdapter template class.
+        *
+        * @see BasicAdapter
+        */
+        class PocoJsonValue
+        {
+        public:
+
+            /// Construct a wrapper for the empty object
+            PocoJsonValue()
+                : value(emptyObject())
+            { }
+
+            /// Construct a wrapper for a specific PocoJson value
+            PocoJsonValue(const Poco::Dynamic::Var& value)
+                : value(value)
+            { }
+
+            /**
+            * @brief   Create a new PocoJsonFrozenValue instance that contains the
+            *          value referenced by this PocoJsonValue instance.
+            *
+            * @returns pointer to a new PocoJsonFrozenValue instance, belonging to the
+            *          caller.
+            */
+            FrozenValue * freeze() const
+            {
+                return new PocoJsonFrozenValue(value);
+            }
+
+            /**
+            * @brief   Optionally return a PocoJsonArray instance.
+            *
+            * If the referenced PocoJson value is an array, this function will return
+            * a std::optional containing a PocoJsonArray instance referencing the
+            * array.
+            *
+            * Otherwise it will return an empty optional.
+            */
+            opt::optional<PocoJsonArray> getArrayOptional() const
+            {
+                if (value.type() == typeid(Poco::JSON::Array::Ptr)) {
+                    return opt::make_optional(PocoJsonArray(value));
+                }
+
+                return opt::optional<PocoJsonArray>();
+            }
+
+            /**
+            * @brief   Retrieve the number of elements in the array
+            *
+            * If the referenced PocoJson value is an array, this function will
+            * retrieve the number of elements in the array and store it in the output
+            * variable provided.
+            *
+            * @param   result  reference to size_t to set with result
+            *
+            * @returns true if the number of elements was retrieved, false otherwise.
+            */
+            bool getArraySize(size_t &result) const
+            {
+                if (value.type() == typeid(Poco::JSON::Array::Ptr)) {
+                    result = value.extract<Poco::JSON::Array::Ptr>()->size();
+                    return true;
+                }
+
+                return false;
+            }
+
+            bool getBool(bool &result) const
+            {
+                if (value.isBoolean()) {
+                    result = value.convert<bool>();
+                    return true;
+                }
+
+                return false;
+            }
+
+            bool getDouble(double &result) const
+            {
+                if (value.isNumeric() && !value.isInteger()) {
+                    result = value.convert<double>();
+                    return true;
+                }
+
+                return false;
+            }
+
+            bool getInteger(int64_t &result) const
+            {
+                if (value.isInteger()) {
+                    result = value.convert<int>();
+                    return true;
+                }
+                return false;
+            }
+
+            /**
+            * @brief   Optionally return a PocoJsonObject instance.
+            *
+            * If the referenced PocoJson value is an object, this function will return a
+            * std::optional containing a PocoJsonObject instance referencing the
+            * object.
+            *
+            * Otherwise it will return an empty optional.
+            */
+            opt::optional<PocoJsonObject> getObjectOptional() const
+            {
+                if (value.type() == typeid(Poco::JSON::Object::Ptr)) {
+                    return opt::make_optional(PocoJsonObject(value));
+                }
+
+                return opt::optional<PocoJsonObject>();
+            }
+
+            /**
+            * @brief   Retrieve the number of members in the object
+            *
+            * If the referenced PocoJson value is an object, this function will
+            * retrieve the number of members in the object and store it in the output
+            * variable provided.
+            *
+            * @param   result  reference to size_t to set with result
+            *
+            * @returns true if the number of members was retrieved, false otherwise.
+            */
+            bool getObjectSize(size_t &result) const
+            {
+                if (value.type() == typeid(Poco::JSON::Object::Ptr)) {
+                    result = value.extract<Poco::JSON::Object::Ptr>()->size();
+                    return true;
+                }
+
+                return false;
+            }
+
+            bool getString(std::string &result) const
+            {
+                if (value.isString()) {
+                    result = value.convert<std::string>();
+                    return true;
+                }
+
+                return false;
+            }
+
+            static bool hasStrictTypes()
+            {
+                return true;
+            }
+
+            bool isArray() const
+            {
+                return value.type() == typeid(Poco::JSON::Array::Ptr);
+            }
+
+            bool isBool() const
+            {
+                return value.isBoolean();
+            }
+
+            bool isDouble() const
+            {
+                return value.isNumeric() && !value.isInteger();
+            }
+
+            bool isInteger() const
+            {
+                return !isBool() && value.isInteger();
+            }
+
+            bool isNull() const
+            {
+                return value.isEmpty();
+            }
+
+            bool isNumber() const
+            {
+                return value.isNumeric();
+            }
+
+            bool isObject() const
+            {
+                return value.type() == typeid(Poco::JSON::Object::Ptr);
+            }
+
+            bool isString() const
+            {
+                return value.isString();
+            }
+
+        private:
+
+            /// Return an empty object
+            static Poco::Dynamic::Var emptyObject()
+            {
+                Poco::Dynamic::Var object = Poco::JSON::Object::Ptr();
+                return object;
+            }
+
+            /// Contained value
+            Poco::Dynamic::Var value;
+        };
+
+        /**
+        * @brief   An implementation of the Adapter interface supporting PocoJson.
+        *
+        * This class is defined in terms of the BasicAdapter template class, which
+        * helps to ensure that all of the Adapter implementations behave consistently.
+        *
+        * @see Adapter
+        * @see BasicAdapter
+        */
+        class PocoJsonAdapter :
+            public BasicAdapter<PocoJsonAdapter,
+            PocoJsonArray,
+            PocoJsonObjectMember,
+            PocoJsonObject,
+            PocoJsonValue>
+        {
+        public:
+            /// Construct a PocoJsonAdapter that contains an empty object
+            PocoJsonAdapter()
+                : BasicAdapter()
+            { }
+
+            /// Construct a PocoJsonAdapter containing a specific Poco Json object
+            PocoJsonAdapter(const Poco::Dynamic::Var &value)
+                : BasicAdapter(PocoJsonValue {value})
+            { }
+        };
+
+        /**
+        * @brief   Class for iterating over values held in a JSON array.
+        *
+        * This class provides a JSON array iterator that dereferences as an instance of
+        * PocoJsonAdapter representing a value stored in the array. It has been
+        * implemented using the boost iterator_facade template.
+        *
+        * @see PocoJsonArray
+        */
+        class PocoJsonArrayValueIterator :
+            public std::iterator<
+            std::bidirectional_iterator_tag,  // bi-directional iterator
+            PocoJsonAdapter>                 // value type
+        {
+        public:
+
+            /**
+            * @brief   Construct a new PocoJsonArrayValueIterator using an existing
+            *          PocoJson iterator.
+            *
+            * @param   itr  PocoJson iterator to store
+            */
+            PocoJsonArrayValueIterator(const Poco::JSON::Array::ConstIterator &itr)
+                : itr(itr)
+            { }
+
+            /// Returns a PocoJsonAdapter that contains the value of the current
+            /// element.
+            PocoJsonAdapter operator*() const
+            {
+                return PocoJsonAdapter(*itr);
+            }
+
+            DerefProxy<PocoJsonAdapter> operator->() const
+            {
+                return DerefProxy<PocoJsonAdapter>(**this);
+            }
+
+            /**
+            * @brief   Compare this iterator against another iterator.
+            *
+            * Note that this directly compares the iterators, not the underlying
+            * values, and assumes that two identical iterators will point to the same
+            * underlying object.
+            *
+            * @param   other  iterator to compare against
+            *
+            * @returns true   if the iterators are equal, false otherwise.
+            */
+            bool operator==(const PocoJsonArrayValueIterator &other) const
+            {
+                return itr == other.itr;
+            }
+
+            bool operator!=(const PocoJsonArrayValueIterator &other) const
+            {
+                return !(itr == other.itr);
+            }
+
+            const PocoJsonArrayValueIterator& operator++()
+            {
+                itr++;
+
+                return *this;
+            }
+
+            PocoJsonArrayValueIterator operator++(int)
+            {
+                PocoJsonArrayValueIterator iterator_pre(itr);
+                ++(*this);
+                return iterator_pre;
+            }
+
+            const PocoJsonArrayValueIterator& operator--()
+            {
+                itr--;
+
+                return *this;
+            }
+
+            void advance(std::ptrdiff_t n)
+            {
+                itr += n;
+            }
+
+        private:
+            Poco::JSON::Array::ConstIterator itr;
+        };
+
+
+        /**
+        * @brief   Class for iterating over the members belonging to a JSON object.
+        *
+        * This class provides a JSON object iterator that dereferences as an instance
+        * of PocoJsonObjectMember representing one of the members of the object. It
+        * has been implemented using the boost iterator_facade template.
+        *
+        * @see PocoJsonObject
+        * @see PocoJsonObjectMember
+        */
+        class PocoJsonObjectMemberIterator :
+            public std::iterator<
+            std::bidirectional_iterator_tag,     // bi-directional iterator
+            PocoJsonObjectMember>            // value type
+        {
+        public:
+
+            /**
+            * @brief   Construct an iterator from a PocoJson iterator.
+            *
+            * @param   itr  PocoJson iterator to store
+            */
+            PocoJsonObjectMemberIterator(const Poco::JSON::Object::ConstIterator &itr)
+                : itr(itr)
+            { }
+
+            /**
+            * @brief   Returns a PocoJsonObjectMember that contains the key and value
+            *          belonging to the object member identified by the iterator.
+            */
+            PocoJsonObjectMember operator*() const
+            {
+                return PocoJsonObjectMember(itr->first, itr->second);
+            }
+
+            DerefProxy<PocoJsonObjectMember> operator->() const
+            {
+                return DerefProxy<PocoJsonObjectMember>(**this);
+            }
+
+            /**
+            * @brief   Compare this iterator with another iterator.
+            *
+            * Note that this directly compares the iterators, not the underlying
+            * values, and assumes that two identical iterators will point to the same
+            * underlying object.
+            *
+            * @param   other  Iterator to compare with
+            *
+            * @returns true if the underlying iterators are equal, false otherwise
+            */
+            bool operator==(const PocoJsonObjectMemberIterator &other) const
+            {
+                return itr == other.itr;
+            }
+
+            bool operator!=(const PocoJsonObjectMemberIterator &other) const
+            {
+                return !(itr == other.itr);
+            }
+
+            const PocoJsonObjectMemberIterator& operator++()
+            {
+                itr++;
+
+                return *this;
+            }
+
+            PocoJsonObjectMemberIterator operator++(int)
+            {
+                PocoJsonObjectMemberIterator iterator_pre(itr);
+                ++(*this);
+                return iterator_pre;
+            }
+
+            const PocoJsonObjectMemberIterator& operator--()
+            {
+                itr--;
+
+                return *this;
+            }
+
+        private:
+
+            /// Iternal copy of the original PocoJson iterator
+            Poco::JSON::Object::ConstIterator itr;
+        };
+
+        /// Specialisation of the AdapterTraits template struct for PocoJsonAdapter.
+        template<>
+        struct AdapterTraits<valijson::adapters::PocoJsonAdapter>
+        {
+            typedef Poco::Dynamic::Var DocumentType;
+
+            static std::string adapterName()
+            {
+                return "PocoJsonAdapter";
+            }
+        };
+
+        inline PocoJsonArrayValueIterator PocoJsonArray::begin() const
+        {
+            return value.extract<Poco::JSON::Array::Ptr>()->begin();
+        }
+
+        inline PocoJsonArrayValueIterator PocoJsonArray::end() const
+        {
+            return value.extract<Poco::JSON::Array::Ptr>()->end();
+        }
+
+        inline PocoJsonObjectMemberIterator PocoJsonObject::begin() const
+        {
+            return value.extract<Poco::JSON::Object::Ptr>()->begin();
+        }
+
+        inline PocoJsonObjectMemberIterator PocoJsonObject::end() const
+        {
+            return value.extract<Poco::JSON::Object::Ptr>()->end();
+        }
+
+        inline PocoJsonObjectMemberIterator PocoJsonObject::find(
+            const std::string &propertyName) const
+        {
+            auto& ptr = value.extract<Poco::JSON::Object::Ptr>();
+
+            auto it = std::find_if(ptr->begin(), ptr->end(),
+                                   [&propertyName](const Poco::JSON::Object::ValueType& p)
+            {
+                return p.first == propertyName;
+            });
+            return it;
+        }
+
+        inline bool PocoJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
+        {
+            return PocoJsonAdapter(value).equalTo(other, strict);
+        }
+
+
+        
+
+    }  // namespace adapters
+}  // namespace valijson
+
+#endif // __VALIJSON_ADAPTERS_POCO_JSON_ADAPTER_HPP
+
diff --git a/examples/validator/valijson/include/valijson/adapters/property_tree_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/property_tree_adapter.hpp
new file mode 100644
index 0000000..5ee7117
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/property_tree_adapter.hpp
@@ -0,0 +1,757 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the Boost property tree library.
+ *
+ * Include this file in your program to enable support for boost property trees.
+ *
+ * This file defines the following classes (not in this order):
+ *  - PropertyTreeAdapter
+ *  - PropertyTreeArray
+ *  - PropertyTreeArrayValueIterator
+ *  - PropertyTreeFrozenValue
+ *  - PropertyTreeObject
+ *  - PropertyTreeObjectMember
+ *  - PropertyTreeObjectMemberIterator
+ *  - PropertyTreeValue
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is PropertyTreeAdapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_PROPERTY_TREE_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_PROPERTY_TREE_ADAPTER_HPP
+
+#include <string>
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+class PropertyTreeAdapter;
+class PropertyTreeArrayValueIterator;
+class PropertyTreeObjectMemberIterator;
+
+typedef std::pair<std::string, PropertyTreeAdapter> PropertyTreeObjectMember;
+
+/**
+ * @brief   Light weight wrapper for a Boost property tree that contains
+ *          array-like data.
+ *
+ * This class is light weight wrapper for a Boost property tree. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to a Boost property
+ * tree that is assumed to contain unnamed key-value pairs. There is very little
+ * associated with copy construction and passing by value.
+ */
+class PropertyTreeArray
+{
+public:
+
+    typedef PropertyTreeArrayValueIterator const_iterator;
+    typedef PropertyTreeArrayValueIterator iterator;
+
+    /// Construct a PropertyTreeArra7 referencing an empty property tree
+    /// singleton.
+    PropertyTreeArray()
+      : array(emptyTree()) { }
+
+    /**
+     * @brief   Construct PropertyTreeArray referencing a specific Boost
+     *          property tree.
+     *
+     * @param   array   reference to a property tree containing an array
+     *
+     * It is assumed that this value contains array-like data, but this is not
+     * checked due to runtime cost.
+     */
+    explicit PropertyTreeArray(const boost::property_tree::ptree &array)
+      : array(array) { }
+
+    /// Return an iterator for the first element in the array.
+    PropertyTreeArrayValueIterator begin() const;
+
+    /// Return an iterator for one-past the last element of the array.
+    PropertyTreeArrayValueIterator end() const;
+
+    /// Return the number of elements in the array
+    size_t size() const
+    {
+        return array.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a property tree that looks like an
+     *          empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const boost::property_tree::ptree & emptyTree()
+    {
+        static const boost::property_tree::ptree tree;
+        return tree;
+    }
+
+    /// Reference to the contained value
+    const boost::property_tree::ptree &array;
+};
+
+/**
+ * @brief  Light weight wrapper for a Boost property tree that contains
+ *         object-like data.
+ *
+ * This class is light weight wrapper for a Boost property tree. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * property tree value, assumed to be object-like, so there is very little
+ * overhead associated with copy construction and passing by value.
+ */
+class PropertyTreeObject
+{
+public:
+
+    typedef PropertyTreeObjectMemberIterator const_iterator;
+    typedef PropertyTreeObjectMemberIterator iterator;
+
+    /// Construct a PropertyTreeObject referencing an empty property tree.
+    PropertyTreeObject()
+      : object(emptyTree()) { }
+
+    /**
+     * @brief   Construct a PropertyTreeObject referencing a specific property
+     *          tree.
+     *
+     * @param   object  reference to a property tree containing an object
+     *
+     * Note that the value of the property tree is not checked, due to the
+     * runtime cost of doing so.
+     */
+    PropertyTreeObject(const boost::property_tree::ptree &object)
+      : object(object) { }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying property tree
+     * implementation.
+     */
+    PropertyTreeObjectMemberIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the pointer value returned by the underlying property tree
+     * implementation.
+     */
+    PropertyTreeObjectMemberIterator end() const;
+
+    /**
+     * @brief   Return an iterator for the object member with the specified
+     *          property name.
+     *
+     * If an object member with the specified name does not exist, the iterator
+     * returned will be the same as the iterator returned by the end() function.
+     *
+     * @param   property   property name to search for
+     */
+    PropertyTreeObjectMemberIterator find(const std::string &property) const;
+
+    /// Returns the number of members belonging to this object.
+    size_t size() const
+    {
+        return object.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to an empty property tree.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const boost::property_tree::ptree & emptyTree()
+    {
+        static const boost::property_tree::ptree tree;
+        return tree;
+    }
+
+    /// Reference to the contained object
+    const boost::property_tree::ptree &object;
+
+};
+
+/**
+ * @brief   Stores an independent copy of a Boost property tree.
+ *
+ * This class allows a property tree value to be stored independent of its
+ * original 'document'. Boost property trees make this easy to do, as they do
+ * not perform any custom memory management.
+ *
+ * @see FrozenValue
+ */
+class PropertyTreeFrozenValue: public FrozenValue
+{
+public:
+
+    /**
+     * @brief  Make a copy of a Boost property tree POD value
+     *
+     * @param  source  string containing the POD vlaue
+     */
+    explicit PropertyTreeFrozenValue(
+            const boost::property_tree::ptree::data_type &source)
+      : value(source) { }
+
+    /**
+     * @brief  Make a copy of a Boost property tree object or array value
+     *
+     * @param  source  the property tree to be copied
+     */
+    explicit PropertyTreeFrozenValue(
+            const boost::property_tree::ptree &source)
+      : value(source) { }
+
+    virtual FrozenValue * clone() const
+    {
+        return new PropertyTreeFrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /// Stored value
+    boost::property_tree::ptree value;
+};
+
+/**
+ * @brief   Light weight wrapper for a Boost property tree.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a Boost property tree value. This class
+ * is responsible for the mechanics of actually reading a property tree, whereas
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+class PropertyTreeValue
+{
+public:
+
+    /// Construct a wrapper for an empty property tree
+    PropertyTreeValue()
+      : object(emptyTree()) { }
+
+    /**
+     * @brief  Construct a PropertyTreeValue from a tree object
+     *
+     * This function will determine whether the tree object represents an array
+     * or an object by scanning the key names for any non-empty strings. In the
+     * case of an empty tree object, it is not possible to determine whether it
+     * is an array or an object, so it will be treated as an array by default.
+     * Empty arrays are considered equal to empty objects when compared using
+     * non-strict type comparison. Empty strings will also be stored as empty
+     * arrays.
+     *
+     * @param  tree  Tree object to be wrapped
+     */
+    PropertyTreeValue(const boost::property_tree::ptree &tree)
+    {
+        if (tree.data().empty()) {    // No string content
+            if (tree.size() == 0) {   // No children
+                array.emplace(tree);         // Treat as empty array
+            } else {
+                bool isArray = true;
+                boost::property_tree::ptree::const_iterator itr;
+                for (itr = tree.begin(); itr != tree.end(); itr++) {
+                    if (!itr->first.empty()) {
+                        isArray = false;
+                        break;
+                    }
+                }
+
+                if (isArray) {
+                    array.emplace(tree);
+                } else {
+                    object.emplace(tree);
+                }
+            }
+        } else {
+            value = tree.data();
+        }
+    }
+
+    /**
+     * @brief   Create a new PropertyTreeFrozenValue instance that contains the
+     *          value referenced by this PropertyTreeValue instance.
+     *
+     * @returns pointer to a new PropertyTreeFrozenValue instance, belonging to
+     *          the caller.
+     */
+    FrozenValue* freeze() const
+    {
+        if (array) {
+            return new PropertyTreeFrozenValue(*array);
+        } else if (object) {
+            return new PropertyTreeFrozenValue(*object);
+        } else {
+            return new PropertyTreeFrozenValue(*value);
+        }
+    }
+
+    /**
+     * @brief  Return an instance of PropertyTreeArrayAdapter.
+     *
+     * If the referenced property tree value is an array, this function will
+     * return a std::optional containing a PropertyTreeArray instance
+     * referencing the array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<PropertyTreeArray> getArrayOptional() const
+    {
+        if (array) {
+            return opt::make_optional(PropertyTreeArray(*array));
+        }
+
+        return opt::optional<PropertyTreeArray>();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced property tree value is an array, this function will
+     * retrieve the number of elements in the array and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (array) {
+            result = array->size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &) const
+    {
+        return false;
+    }
+
+    bool getDouble(double &) const
+    {
+        return false;
+    }
+
+    bool getInteger(int64_t &) const
+    {
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a PropertyTreeObject instance.
+     *
+     * If the referenced property tree is an object, this function will return a
+     * std::optional containing a PropertyTreeObject instance referencing the
+     * object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<PropertyTreeObject> getObjectOptional() const
+    {
+        if (object) {
+            return opt::make_optional(PropertyTreeObject(*object));
+        }
+
+        return opt::optional<PropertyTreeObject>();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced property tree value is an object, this function will
+     * retrieve the number of members in the object and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (object) {
+            result = object->size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value) {
+            result = *value;
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return false;
+    }
+
+    bool isArray() const
+    {
+        return static_cast<bool>(array);
+    }
+
+    bool isBool() const
+    {
+        return false;
+    }
+
+    bool isDouble() const
+    {
+        return false;
+    }
+
+    bool isInteger() const
+    {
+        return false;
+    }
+
+    bool isNull() const
+    {
+        return false;
+    }
+
+    bool isNumber() const
+    {
+        return false;
+    }
+
+    bool isObject() const
+    {
+        return static_cast<bool>(object);
+    }
+
+    bool isString() const
+    {
+        return static_cast<bool>(value);
+    }
+
+private:
+
+    static const boost::property_tree::ptree & emptyTree()
+    {
+        static const boost::property_tree::ptree tree;
+        return tree;
+    }
+
+    /// Reference used if the value is known to be an array
+    opt::optional<const boost::property_tree::ptree &> array;
+
+    /// Reference used if the value is known to be an object
+    opt::optional<const boost::property_tree::ptree &> object;
+
+    /// Reference used if the value is known to be a POD type
+    opt::optional<std::string> value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting the Boost
+ *          property tree library.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+class PropertyTreeAdapter:
+    public BasicAdapter<PropertyTreeAdapter,
+                        PropertyTreeArray,
+                        PropertyTreeObjectMember,
+                        PropertyTreeObject,
+                        PropertyTreeValue>
+{
+public:
+
+    /// Construct a PropertyTreeAdapter for an empty property tree
+    PropertyTreeAdapter()
+      : BasicAdapter() { }
+
+    /// Construct a PropertyTreeAdapter using a specific property tree
+    PropertyTreeAdapter(const boost::property_tree::ptree &value)
+      : BasicAdapter(value) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * PropertyTreeAdapter representing a value stored in the array. It has been
+ * implemented using the boost iterator_facade template.
+ *
+ * @see PropertyTreeArray
+ */
+class PropertyTreeArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,    // bi-directional iterator
+        PropertyTreeAdapter>                // value type
+{
+public:
+
+    /**
+     * @brief   Construct a new PropertyTreeArrayValueIterator using an existing
+     *          property tree iterator.
+     *
+     * @param   itr  property tree iterator to store
+     */
+    PropertyTreeArrayValueIterator(
+        const boost::property_tree::ptree::const_iterator &itr)
+      : itr(itr) { }
+
+    /// Returns a PropertyTreeAdapter that contains the value of the current
+    /// element.
+    PropertyTreeAdapter operator*() const
+    {
+        return PropertyTreeAdapter(itr->second);
+    }
+
+    DerefProxy<PropertyTreeAdapter> operator->() const
+    {
+        return DerefProxy<PropertyTreeAdapter>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   rhs  iterator to compare against
+     *
+     * @returns true if the iterators are equal, false otherwise.
+     */
+    bool operator==(const PropertyTreeArrayValueIterator &rhs) const
+    {
+        return itr == rhs.itr;
+    }
+
+    bool operator!=(const PropertyTreeArrayValueIterator &rhs) const
+    {
+        return !(itr == rhs.itr);
+    }
+
+    const PropertyTreeArrayValueIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    PropertyTreeArrayValueIterator operator++(int)
+    {
+        PropertyTreeArrayValueIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const PropertyTreeArrayValueIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        if (n > 0) {
+            while (n-- > 0) {
+                itr++;
+            }
+        } else {
+            while (n++ < 0) {
+                itr--;
+            }
+        }
+    }
+
+private:
+
+    boost::property_tree::ptree::const_iterator itr;
+};
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of PropertyTreeObjectMember representing one of the members of the object.
+ * It has been implemented using the boost iterator_facade template.
+ *
+ * @see PropertyTreeObject
+ * @see PropertyTreeObjectMember
+ */
+class PropertyTreeObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,     // bi-directional iterator
+        PropertyTreeObjectMember>            // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a PropertyTree iterator.
+     *
+     * @param   itr  PropertyTree iterator to store
+     */
+    PropertyTreeObjectMemberIterator(
+        boost::property_tree::ptree::const_assoc_iterator itr)
+      : itr(itr) { }
+
+    /**
+     * @brief   Returns a PropertyTreeObjectMember that contains the key and
+     *          value belonging to the object member identified by the iterator.
+     */
+    PropertyTreeObjectMember operator*() const
+    {
+        return PropertyTreeObjectMember(itr->first, itr->second);
+    }
+
+    DerefProxy<PropertyTreeObjectMember> operator->() const
+    {
+        return DerefProxy<PropertyTreeObjectMember>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   rhs  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const PropertyTreeObjectMemberIterator &rhs) const
+    {
+        return itr == rhs.itr;
+    }
+
+    bool operator!=(const PropertyTreeObjectMemberIterator &rhs) const
+    {
+        return !(itr == rhs.itr);
+    }
+
+    const PropertyTreeObjectMemberIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    PropertyTreeObjectMemberIterator operator++(int)
+    {
+        PropertyTreeObjectMemberIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const PropertyTreeObjectMemberIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+private:
+
+    boost::property_tree::ptree::const_assoc_iterator itr;
+};
+
+/// Specialisation of the AdapterTraits template struct for PropertyTreeAdapter.
+template<>
+struct AdapterTraits<valijson::adapters::PropertyTreeAdapter>
+{
+    typedef boost::property_tree::ptree DocumentType;
+
+    static std::string adapterName()
+    {
+        return "PropertyTreeAdapter";
+    }
+};
+
+inline bool PropertyTreeFrozenValue::equalTo(const Adapter &other, bool strict) const
+{
+    return PropertyTreeAdapter(value).equalTo(other, strict);
+}
+
+inline PropertyTreeArrayValueIterator PropertyTreeArray::begin() const
+{
+    return array.begin();
+}
+
+inline PropertyTreeArrayValueIterator PropertyTreeArray::end() const
+{
+    return array.end();
+}
+
+inline PropertyTreeObjectMemberIterator PropertyTreeObject::begin() const
+{
+    return object.ordered_begin();
+}
+
+inline PropertyTreeObjectMemberIterator PropertyTreeObject::end() const
+{
+    return object.not_found();
+}
+
+inline PropertyTreeObjectMemberIterator PropertyTreeObject::find(
+    const std::string &propertyName) const
+{
+    const boost::property_tree::ptree::const_assoc_iterator
+        itr = object.find(propertyName);
+
+    if (itr != object.not_found()) {
+        return itr;
+    }
+
+    return object.not_found();
+}
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/qtjson_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/qtjson_adapter.hpp
new file mode 100644
index 0000000..9422d25
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/qtjson_adapter.hpp
@@ -0,0 +1,725 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the QtJson parser library.
+ *
+ * Include this file in your program to enable support for QtJson.
+ *
+ * This file defines the following classes (not in this order):
+ *  - QtJsonAdapter
+ *  - QtJsonArray
+ *  - QtJsonArrayValueIterator
+ *  - QtJsonFrozenValue
+ *  - QtJsonObject
+ *  - QtJsonObjectMember
+ *  - QtJsonObjectMemberIterator
+ *  - QtJsonValue
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is QtJsonAdapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_QTJSON_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_QTJSON_ADAPTER_HPP
+
+#include <string>
+
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QJsonArray>
+
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+class QtJsonAdapter;
+class QtJsonArrayValueIterator;
+class QtJsonObjectMemberIterator;
+
+typedef std::pair<std::string, QtJsonAdapter> QtJsonObjectMember;
+
+/**
+ * @brief  Light weight wrapper for a QtJson array value.
+ *
+ * This class is light weight wrapper for a QtJson array. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * QtJson value, assumed to be an array, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class QtJsonArray
+{
+public:
+
+    typedef QtJsonArrayValueIterator const_iterator;
+    typedef QtJsonArrayValueIterator iterator;
+
+    /// Construct a QtJsonArray referencing an empty array.
+    QtJsonArray()
+      : value(emptyArray())
+    {
+    }
+
+    /**
+     * @brief   Construct a QtJsonArray referencing a specific QtJson
+     *          value.
+     *
+     * @param   value   reference to a QtJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an array.
+     */
+    explicit QtJsonArray(const QJsonValue &value)
+      : value(value.toArray())
+    {
+        if (!value.isArray()) {
+            throw std::runtime_error("Value is not an array.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for the first element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying QtJson implementation.
+     */
+    QtJsonArrayValueIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for one-past the last element of the array.
+     *
+     * The iterator return by this function is effectively the iterator
+     * returned by the underlying QtJson implementation.
+     */
+    QtJsonArrayValueIterator end() const;
+
+    /// Return the number of elements in the array
+    size_t size() const
+    {
+        return value.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a QtJson value that is an empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const QJsonArray emptyArray()
+    {
+        static const QJsonArray array;
+        return array;
+    }
+
+    /// Reference to the contained value
+    const QJsonArray value;
+};
+
+/**
+ * @brief  Light weight wrapper for a QtJson object.
+ *
+ * This class is light weight wrapper for a QtJson object. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * QtJson value, assumed to be an object, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+class QtJsonObject
+{
+public:
+
+    typedef QtJsonObjectMemberIterator const_iterator;
+    typedef QtJsonObjectMemberIterator iterator;
+
+    /// Construct a QtJsonObject referencing an empty object singleton.
+    QtJsonObject()
+      : value(emptyObject())
+    {
+    }
+
+    /**
+     * @brief   Construct a QtJsonObject referencing a specific QtJson
+     *          value.
+     *
+     * @param   value  reference to a QtJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an object.
+     */
+    QtJsonObject(const QJsonValue &value)
+      : value(value.toObject())
+    {
+        if (!value.isObject()) {
+            throw std::runtime_error("Value is not an object.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying QtJson implementation.
+     */
+    QtJsonObjectMemberIterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the iterator value returned by the underlying QtJson implementation.
+     */
+    QtJsonObjectMemberIterator end() const;
+
+    /**
+     * @brief   Return an iterator for the object member with the specified
+     *          property name.
+     *
+     * If an object member with the specified name does not exist, the iterator
+     * returned will be the same as the iterator returned by the end() function.
+     *
+     * @param   propertyName  property name to search for
+     */
+    QtJsonObjectMemberIterator find(const std::string &propertyName) const;
+
+    /// Returns the number of members belonging to this object.
+    size_t size() const
+    {
+        return value.size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a QtJson value that is empty object.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const QJsonObject emptyObject()
+    {
+        static const QJsonObject object;
+        return object;
+    }
+
+    /// Reference to the contained object
+    const QJsonObject value;
+};
+
+/**
+ * @brief   Stores an independent copy of a QtJson value.
+ *
+ * This class allows a QtJson value to be stored independent of its original
+ * document. QtJson makes this easy to do, as it does not perform any
+ * custom memory management.
+ *
+ * @see FrozenValue
+ */
+class QtJsonFrozenValue: public FrozenValue
+{
+public:
+
+    /**
+     * @brief  Make a copy of a QtJson value
+     *
+     * @param  source  the QtJson value to be copied
+     */
+    explicit QtJsonFrozenValue(const QJsonValue &source)
+      : value(source) { }
+
+    virtual FrozenValue * clone() const
+    {
+        return new QtJsonFrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /// Stored QtJson value
+    QJsonValue value;
+};
+
+/**
+ * @brief   Light weight wrapper for a QtJson value.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a QtJson value. This class is responsible
+ * for the mechanics of actually reading a QtJson value, whereas the
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+class QtJsonValue
+{
+public:
+
+    /// Construct a wrapper for the empty object singleton
+    QtJsonValue()
+      : value(emptyObject()) { }
+
+    /// Construct a wrapper for a specific QtJson value
+    QtJsonValue(const QJsonValue &value)
+      : value(value) { }
+
+    /**
+     * @brief   Create a new QtJsonFrozenValue instance that contains the
+     *          value referenced by this QtJsonValue instance.
+     *
+     * @returns pointer to a new QtJsonFrozenValue instance, belonging to the
+     *          caller.
+     */
+    FrozenValue * freeze() const
+    {
+        return new QtJsonFrozenValue(value);
+    }
+
+    /**
+     * @brief   Optionally return a QtJsonArray instance.
+     *
+     * If the referenced QtJson value is an array, this function will return
+     * a std::optional containing a QtJsonArray instance referencing the
+     * array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<QtJsonArray> getArrayOptional() const
+    {
+        if (value.isArray()) {
+            return opt::make_optional(QtJsonArray(value));
+        }
+
+        return opt::optional<QtJsonArray>();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced QtJson value is an array, this function will
+     * retrieve the number of elements in the array and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (value.isArray()) {
+            const QJsonArray array = value.toArray();
+            result = array.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &result) const
+    {
+        if (value.isBool()) {
+            result = value.toBool();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getDouble(double &result) const
+    {
+        if (value.isDouble()) {
+            result = value.toDouble();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getInteger(int64_t &result) const
+    {
+        if (value.isDouble()) {
+            result = value.toInt();
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a QtJsonObject instance.
+     *
+     * If the referenced QtJson value is an object, this function will return a
+     * std::optional containing a QtJsonObject instance referencing the
+     * object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<QtJsonObject> getObjectOptional() const
+    {
+        if (value.isObject()) {
+            return opt::make_optional(QtJsonObject(value));
+        }
+
+        return opt::optional<QtJsonObject>();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced QtJson value is an object, this function will
+     * retrieve the number of members in the object and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (value.isObject()) {
+            const QJsonObject &object = value.toObject();
+            result = object.size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value.isString()) {
+            result = value.toString().toStdString();
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return true;
+    }
+
+    bool isArray() const
+    {
+        return value.isArray();
+    }
+
+    bool isBool() const
+    {
+        return value.isBool();
+    }
+
+    bool isDouble() const
+    {
+        return value.isDouble();
+    }
+
+    bool isInteger() const
+    {
+        //toInt returns the default value (0, 1) if the value is not a whole number
+        return value.isDouble() && (value.toInt(0) == value.toInt(1));
+    }
+
+    bool isNull() const
+    {
+        return value.isNull();
+    }
+
+    bool isNumber() const
+    {
+        return value.isDouble();
+    }
+
+    bool isObject() const
+    {
+        return value.isObject();
+    }
+
+    bool isString() const
+    {
+        return value.isString();
+    }
+
+private:
+
+    /// Return a reference to an empty object singleton
+    static const QJsonValue emptyObject()
+    {
+        static const QJsonValue object;
+        return object;
+    }
+
+    /// Reference to the contained QtJson value.
+    const QJsonValue value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting QtJson.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+class QtJsonAdapter:
+    public BasicAdapter<QtJsonAdapter,
+                        QtJsonArray,
+                        QtJsonObjectMember,
+                        QtJsonObject,
+                        QtJsonValue>
+{
+public:
+
+    /// Construct a QtJsonAdapter that contains an empty object
+    QtJsonAdapter()
+      : BasicAdapter() { }
+
+    /// Construct a QtJsonAdapter containing a specific QtJson value
+    QtJsonAdapter(const QJsonValue &value)
+      : BasicAdapter(value) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * QtJsonAdapter representing a value stored in the array. It has been
+ * implemented using the std::iterator template.
+ *
+ * @see QtJsonArray
+ */
+class QtJsonArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,     // bi-directional iterator
+        QtJsonAdapter>                     // value type
+{
+public:
+
+    /**
+     * @brief   Construct a new QtJsonArrayValueIterator using an existing
+     *          QtJson iterator.
+     *
+     * @param   itr  QtJson iterator to store
+     */
+    QtJsonArrayValueIterator(
+        const QJsonArray::const_iterator &itr)
+      : itr(itr) { }
+
+    /// Returns a QtJsonAdapter that contains the value of the current
+    /// element.
+    QtJsonAdapter operator*() const
+    {
+        return QtJsonAdapter(*itr);
+    }
+
+    DerefProxy<QtJsonAdapter> operator->() const
+    {
+        return DerefProxy<QtJsonAdapter>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  iterator to compare against
+     *
+     * @returns true   if the iterators are equal, false otherwise.
+     */
+    bool operator==(const QtJsonArrayValueIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const QtJsonArrayValueIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const QtJsonArrayValueIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    QtJsonArrayValueIterator operator++(int)
+    {
+        QtJsonArrayValueIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const QtJsonArrayValueIterator& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        itr += n;
+    }
+
+private:
+
+    QJsonArray::const_iterator itr;
+};
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of QtJsonObjectMember representing one of the members of the object. It
+ * has been implemented using the boost iterator_facade template.
+ *
+ * @see QtJsonObject
+ * @see QtJsonObjectMember
+ */
+class QtJsonObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,  // bi-directional iterator
+        QtJsonObjectMember>             // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a QtJson iterator.
+     *
+     * @param   itr  QtJson iterator to store
+     */
+    QtJsonObjectMemberIterator(
+        const QJsonObject::const_iterator &itr)
+      : itr(itr) { }
+
+    /**
+     * @brief   Returns a QtJsonObjectMember that contains the key and value
+     *          belonging to the object member identified by the iterator.
+     */
+    QtJsonObjectMember operator*() const
+    {
+        std::string key = itr.key().toStdString();
+        return QtJsonObjectMember(key, itr.value());
+    }
+
+    DerefProxy<QtJsonObjectMember> operator->() const
+    {
+        return DerefProxy<QtJsonObjectMember>(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const QtJsonObjectMemberIterator &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const QtJsonObjectMemberIterator &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    const QtJsonObjectMemberIterator& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    QtJsonObjectMemberIterator operator++(int)
+    {
+        QtJsonObjectMemberIterator iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    const QtJsonObjectMemberIterator& operator--(int)
+    {
+        itr--;
+
+        return *this;
+    }
+
+private:
+
+    /// Iternal copy of the original QtJson iterator
+    QJsonObject::const_iterator itr;
+};
+
+/// Specialisation of the AdapterTraits template struct for QtJsonAdapter.
+template<>
+struct AdapterTraits<valijson::adapters::QtJsonAdapter>
+{
+    typedef QJsonValue DocumentType;
+
+    static std::string adapterName()
+    {
+        return "QtJsonAdapter";
+    }
+};
+
+inline bool QtJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
+{
+    return QtJsonAdapter(value).equalTo(other, strict);
+}
+
+inline QtJsonArrayValueIterator QtJsonArray::begin() const
+{
+    return value.begin();
+}
+
+inline QtJsonArrayValueIterator QtJsonArray::end() const
+{
+    return value.end();
+}
+
+inline QtJsonObjectMemberIterator QtJsonObject::begin() const
+{
+    return value.begin();
+}
+
+inline QtJsonObjectMemberIterator QtJsonObject::end() const
+{
+    return value.end();
+}
+
+inline QtJsonObjectMemberIterator QtJsonObject::find(
+    const std::string &propertyName) const
+{
+    return value.find(QString::fromStdString(propertyName));
+}
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/adapters/rapidjson_adapter.hpp b/examples/validator/valijson/include/valijson/adapters/rapidjson_adapter.hpp
new file mode 100644
index 0000000..38b44b9
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/adapters/rapidjson_adapter.hpp
@@ -0,0 +1,933 @@
+/**
+ * @file
+ *
+ * @brief   Adapter implementation for the RapidJson parser library.
+ *
+ * Include this file in your program to enable support for RapidJson.
+ *
+ * This file defines the following template classes (not in this order):
+ *  - GenericRapidJsonAdapter
+ *  - GenericRapidJsonArray
+ *  - GenericRapidJsonArrayValueIterator
+ *  - GenericRapidJsonFrozenValue
+ *  - GenericRapidJsonObject
+ *  - GenericRapidJsonObjectMember
+ *  - GenericRapidJsonObjectMemberIterator
+ *  - GenericRapidJsonValue
+ *
+ * All of these classes share a template argument called 'ValueType', which can
+ * be used to choose the underlying the RapidJson value type that is used. This
+ * allows different RapidJson encodings and allocators to be used.
+ *
+ * This file also defines the following typedefs, which use RapidJson's default
+ * ValueType:
+ *  - RapidJsonAdapter
+ *  - RapidJsonArray
+ *  - RapidJsonArrayValueIterator
+ *  - RapidJsonFrozenValue
+ *  - RapidJsonObject
+ *  - RapidJsonObjectMember
+ *  - RapidJsonObjectMemberIterator
+ *  - RapidJsonValue
+ *
+ * Due to the dependencies that exist between these classes, the ordering of
+ * class declarations and definitions may be a bit confusing. The best place to
+ * start is RapidJsonAdapter. This class definition is actually very small,
+ * since most of the functionality is inherited from the BasicAdapter class.
+ * Most of the classes in this file are provided as template arguments to the
+ * inherited BasicAdapter class.
+ */
+
+#pragma once
+#ifndef __VALIJSON_ADAPTERS_RAPIDJSON_ADAPTER_HPP
+#define __VALIJSON_ADAPTERS_RAPIDJSON_ADAPTER_HPP
+
+#include <string>
+#include <iterator>
+
+#include <rapidjson/document.h>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/adapters/basic_adapter.hpp>
+#include <valijson/adapters/frozen_value.hpp>
+
+namespace valijson {
+namespace adapters {
+
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonAdapter;
+
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonArrayValueIterator;
+
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonObjectMemberIterator;
+
+/// Container for a property name and an associated RapidJson value
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonObjectMember :
+        public std::pair<std::string, GenericRapidJsonAdapter<ValueType> >
+{
+private:
+    typedef std::pair<std::string, GenericRapidJsonAdapter<ValueType> > Super;
+
+public:
+    GenericRapidJsonObjectMember(
+            const std::string &name,
+            const GenericRapidJsonAdapter<ValueType> &value)
+      : Super(name, value) { }
+};
+
+/**
+ * @brief   Light weight wrapper for a RapidJson array value.
+ *
+ * This class is light weight wrapper for a RapidJson array. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to an underlying
+ * RapidJson value, assumed to be an array, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonArray
+{
+public:
+
+    typedef GenericRapidJsonArrayValueIterator<ValueType> const_iterator;
+    typedef GenericRapidJsonArrayValueIterator<ValueType> iterator;
+
+    /// Construct a RapidJsonArray referencing an empty array singleton.
+    GenericRapidJsonArray()
+      : value(emptyArray()) { }
+
+    /**
+     * @brief   Construct a RapidJsonArray referencing a specific RapidJson
+     *          value.
+     *
+     * @param   value   reference to a RapidJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an array.
+     */
+    GenericRapidJsonArray(const ValueType &value)
+      : value(value)
+    {
+        if (!value.IsArray()) {
+            throw std::runtime_error("Value is not an array.");
+        }
+    }
+
+    /// Return an iterator for the first element in the array.
+    iterator begin() const;
+
+    /// Return an iterator for one-past the last element of the array.
+    iterator end() const;
+
+    /// Return the number of elements in the array
+    size_t size() const
+    {
+        return value.Size();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a RapidJson value that is an empty array.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const ValueType & emptyArray()
+    {
+        static const ValueType array(rapidjson::kArrayType);
+        return array;
+    }
+
+    /// Reference to the contained value
+    const ValueType &value;
+};
+
+/**
+ * @brief  Light weight wrapper for a RapidJson object.
+ *
+ * This class is light weight wrapper for a RapidJson object. It provides a
+ * minimum set of container functions and typedefs that allow it to be used as
+ * an iterable container.
+ *
+ * An instance of this class contains a single reference to the underlying
+ * RapidJson value, assumed to be an object, so there is very little overhead
+ * associated with copy construction and passing by value.
+ */
+template <class ValueType = rapidjson::Value>
+class GenericRapidJsonObject
+{
+public:
+
+    typedef GenericRapidJsonObjectMemberIterator<ValueType> const_iterator;
+    typedef GenericRapidJsonObjectMemberIterator<ValueType> iterator;
+
+    /// Construct a GenericRapidJsonObject referencing an empty object singleton.
+    GenericRapidJsonObject()
+      : value(emptyObject()) { }
+
+    /**
+     * @brief   Construct a GenericRapidJsonObject referencing a specific
+     *          RapidJson value.
+     *
+     * @param   value  reference to a RapidJson value
+     *
+     * Note that this constructor will throw an exception if the value is not
+     * an object.
+     */
+    GenericRapidJsonObject(const ValueType &value)
+      : value(value)
+    {
+        if (!value.IsObject()) {
+            throw std::runtime_error("Value is not an object.");
+        }
+    }
+
+    /**
+     * @brief   Return an iterator for this first object member
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the pointer value returned by the underlying RapidJson implementation.
+     */
+    iterator begin() const;
+
+    /**
+     * @brief   Return an iterator for an invalid object member that indicates
+     *          the end of the collection.
+     *
+     * The iterator return by this function is effectively a wrapper around
+     * the pointer value returned by the underlying RapidJson implementation.
+     */
+    iterator end() const;
+
+    /**
+     * @brief   Return an iterator for the object member with the specified
+     *          property name.
+     *
+     * If an object member with the specified name does not exist, the iterator
+     * returned will be the same as the iterator returned by the end() function.
+     *
+     * @param   property   property name to search for
+     */
+    iterator find(const std::string &property) const;
+
+    /// Returns the number of members belonging to this object.
+    size_t size() const
+    {
+        return value.MemberEnd() - value.MemberBegin();
+    }
+
+private:
+
+    /**
+     * @brief   Return a reference to a RapidJson value that is empty object.
+     *
+     * Note that the value returned by this function is a singleton.
+     */
+    static const ValueType & emptyObject()
+    {
+        static ValueType object(rapidjson::kObjectType);
+        return object;
+    }
+
+    /// Reference to the contained object
+    const ValueType &value;
+};
+
+/**
+ * @brief   Stores an independent copy of a RapidJson value.
+ *
+ * This class allows a RapidJson value to be stored independent of its original
+ * document. RapidJson makes this a bit harder than usual, because RapidJson
+ * values are associated with a custom memory allocator. As such, RapidJson
+ * values have to be copied recursively, referencing a custom allocator held
+ * by this class.
+ *
+ * @see FrozenValue
+ */
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonFrozenValue: public FrozenValue
+{
+public:
+
+    explicit GenericRapidJsonFrozenValue(const char *str)
+    {
+        value.SetString(str, allocator);
+    }
+
+    explicit GenericRapidJsonFrozenValue(const std::string &str)
+    {
+        value.SetString(str.c_str(), (unsigned int)str.length(), allocator);
+    }
+
+    /**
+     * @brief   Make a copy of a RapidJson value
+     *
+     * @param   source  the RapidJson value to be copied
+     */
+    explicit GenericRapidJsonFrozenValue(const ValueType &source)
+    {
+        if (!copy(source, value, allocator)) {
+            throw std::runtime_error("Failed to copy ValueType");
+        }
+    }
+
+    virtual FrozenValue * clone() const
+    {
+        return new GenericRapidJsonFrozenValue(value);
+    }
+
+    virtual bool equalTo(const Adapter &other, bool strict) const;
+
+private:
+
+    /**
+     * @brief   Recursively copy a RapidJson value using a separate allocator
+     *
+     * @param   source      value to copy from
+     * @param   dest        value to copy into
+     * @param   allocator   reference to an allocator held by this class
+     *
+     * @tparam  Allocator   type of RapidJson Allocator to be used
+     *
+     * @returns true if copied successfully, false otherwise.
+     */
+    template<typename Allocator>
+    static bool copy(const ValueType &source,
+                     ValueType &dest,
+                     Allocator &allocator)
+    {
+        switch (source.GetType()) {
+        case rapidjson::kNullType:
+            dest.SetNull();
+            return true;
+        case rapidjson::kFalseType:
+            dest.SetBool(false);
+            return true;
+        case rapidjson::kTrueType:
+            dest.SetBool(true);
+            return true;
+        case rapidjson::kObjectType:
+            dest.SetObject();
+            for (typename ValueType::ConstMemberIterator itr = source.MemberBegin();
+                itr != source.MemberEnd(); ++itr) {
+                ValueType name(itr->name.GetString(), itr->name.GetStringLength(), allocator);
+                ValueType value;
+                copy(itr->value, value, allocator);
+                dest.AddMember(name, value, allocator);
+            }
+            return true;
+        case rapidjson::kArrayType:
+            dest.SetArray();
+            for (typename ValueType::ConstValueIterator itr = source.Begin(); itr != source.End(); ++itr) {
+                ValueType value;
+                copy(*itr, value, allocator);
+                dest.PushBack(value, allocator);
+            }
+            return true;
+        case rapidjson::kStringType:
+            dest.SetString(source.GetString(), source.GetStringLength(), allocator);
+            return true;
+        case rapidjson::kNumberType:
+            if (source.IsInt()) {
+                dest.SetInt(source.GetInt());
+            } else if (source.IsUint()) {
+                dest.SetUint(source.GetUint());
+            } else if (source.IsInt64()) {
+                dest.SetInt64(source.GetInt64());
+            } else if (source.IsUint64()) {
+                dest.SetUint64(source.GetUint64());
+            } else {
+                dest.SetDouble(source.GetDouble());
+            }
+            return true;
+        default:
+            break;
+        }
+
+        return false;
+    }
+
+    /// Local memory allocator for RapidJson value
+    typename ValueType::AllocatorType allocator;
+
+    /// Local RapidJson value
+    ValueType value;
+};
+
+/**
+ * @brief   Light weight wrapper for a RapidJson value.
+ *
+ * This class is passed as an argument to the BasicAdapter template class,
+ * and is used to provide access to a RapidJson value. This class is responsible
+ * for the mechanics of actually reading a RapidJson value, whereas the
+ * BasicAdapter class is responsible for the semantics of type comparisons
+ * and conversions.
+ *
+ * The functions that need to be provided by this class are defined implicitly
+ * by the implementation of the BasicAdapter template class.
+ *
+ * @see BasicAdapter
+ */
+template<class ValueType = rapidjson::Value>
+class GenericRapidJsonValue
+{
+public:
+    /// Construct a wrapper for the empty object singleton
+    GenericRapidJsonValue()
+      : value(emptyObject()) { }
+
+    /// Construct a wrapper for a specific RapidJson value
+    GenericRapidJsonValue(const ValueType &value)
+      : value(value) { }
+
+    /**
+     * @brief   Create a new GenericRapidJsonFrozenValue instance that contains
+     *          the value referenced by this GenericRapidJsonValue instance.
+     *
+     * @returns pointer to a new GenericRapidJsonFrozenValue instance, belonging
+     *          to the caller.
+     */
+    FrozenValue * freeze() const
+    {
+        return new GenericRapidJsonFrozenValue<ValueType>(value);
+    }
+
+    /**
+     * @brief   Optionally return a GenericRapidJsonArray instance.
+     *
+     * If the referenced RapidJson value is an array, this function will return
+     * a std::optional containing a GenericRapidJsonArray instance referencing
+     * the array.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<GenericRapidJsonArray<ValueType> > getArrayOptional() const
+    {
+        if (value.IsArray()) {
+            return opt::make_optional(GenericRapidJsonArray<ValueType>(value));
+        }
+
+        return opt::optional<GenericRapidJsonArray<ValueType> >();
+    }
+
+    /**
+     * @brief   Retrieve the number of elements in the array
+     *
+     * If the referenced RapidJson value is an array, this function will
+     * retrieve the number of elements in the array and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of elements was retrieved, false otherwise.
+     */
+    bool getArraySize(size_t &result) const
+    {
+        if (value.IsArray()) {
+            result = value.Size();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getBool(bool &result) const
+    {
+        if (value.IsBool()) {
+            result = value.GetBool();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getDouble(double &result) const
+    {
+        if (value.IsDouble()) {
+            result = value.GetDouble();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getInteger(int64_t &result) const
+    {
+        if (value.IsInt()) {
+            result = value.GetInt();
+            return true;
+        } else if (value.IsInt64()) {
+            result = value.GetInt64();
+            return true;
+        } else if (value.IsUint()) {
+            result = static_cast<int64_t>(value.GetUint());
+            return true;
+        } else if (value.IsUint64()) {
+            result = static_cast<int64_t>(value.GetUint64());
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Optionally return a GenericRapidJsonObject instance.
+     *
+     * If the referenced RapidJson value is an object, this function will return
+     * a std::optional containing a GenericRapidJsonObject instance
+     * referencing the object.
+     *
+     * Otherwise it will return an empty optional.
+     */
+    opt::optional<GenericRapidJsonObject<ValueType> > getObjectOptional() const
+    {
+        if (value.IsObject()) {
+            return opt::make_optional(GenericRapidJsonObject<ValueType>(value));
+        }
+
+        return opt::optional<GenericRapidJsonObject<ValueType> >();
+    }
+
+    /**
+     * @brief   Retrieve the number of members in the object
+     *
+     * If the referenced RapidJson value is an object, this function will
+     * retrieve the number of members in the object and store it in the output
+     * variable provided.
+     *
+     * @param   result  reference to size_t to set with result
+     *
+     * @returns true if the number of members was retrieved, false otherwise.
+     */
+    bool getObjectSize(size_t &result) const
+    {
+        if (value.IsObject()) {
+            result = value.MemberEnd() - value.MemberBegin();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool getString(std::string &result) const
+    {
+        if (value.IsString()) {
+            result.assign(value.GetString(), value.GetStringLength());
+            return true;
+        }
+
+        return false;
+    }
+
+    static bool hasStrictTypes()
+    {
+        return true;
+    }
+
+    bool isArray() const
+    {
+        return value.IsArray();
+    }
+
+    bool isBool() const
+    {
+        return value.IsBool();
+    }
+
+    bool isDouble() const
+    {
+        return value.IsDouble();
+    }
+
+    bool isInteger() const
+    {
+        return value.IsInt() || value.IsInt64() || value.IsUint() ||
+               value.IsUint64();
+    }
+
+    bool isNull() const
+    {
+        return value.IsNull();
+    }
+
+    bool isNumber() const
+    {
+        return value.IsNumber();
+    }
+
+    bool isObject() const
+    {
+        return value.IsObject();
+    }
+
+    bool isString() const
+    {
+        return value.IsString();
+    }
+
+private:
+
+    /// Return a reference to an empty object singleton
+    static const ValueType & emptyObject()
+    {
+        static const ValueType object(rapidjson::kObjectType);
+        return object;
+    }
+
+    /// Reference to the contained RapidJson value.
+    const ValueType &value;
+};
+
+/**
+ * @brief   An implementation of the Adapter interface supporting RapidJson.
+ *
+ * This class is defined in terms of the BasicAdapter template class, which
+ * helps to ensure that all of the Adapter implementations behave consistently.
+ *
+ * @see Adapter
+ * @see BasicAdapter
+ */
+template<class ValueType>
+class GenericRapidJsonAdapter:
+    public BasicAdapter<GenericRapidJsonAdapter<ValueType>,
+                        GenericRapidJsonArray<ValueType>,
+                        GenericRapidJsonObjectMember<ValueType>,
+                        GenericRapidJsonObject<ValueType>,
+                        GenericRapidJsonValue<ValueType> >
+{
+public:
+
+    /// Construct a RapidJsonAdapter that contains an empty object
+    GenericRapidJsonAdapter()
+      : BasicAdapter<GenericRapidJsonAdapter<ValueType>,
+                        GenericRapidJsonArray<ValueType>,
+                        GenericRapidJsonObjectMember<ValueType>,
+                        GenericRapidJsonObject<ValueType>,
+                        GenericRapidJsonValue<ValueType> >() { }
+
+    /// Construct a RapidJsonAdapter containing a specific RapidJson value
+    GenericRapidJsonAdapter(const ValueType &value)
+      : BasicAdapter<GenericRapidJsonAdapter<ValueType>,
+                        GenericRapidJsonArray<ValueType>,
+                        GenericRapidJsonObjectMember<ValueType>,
+                        GenericRapidJsonObject<ValueType>,
+                        GenericRapidJsonValue<ValueType> >(value) { }
+};
+
+/**
+ * @brief   Class for iterating over values held in a JSON array.
+ *
+ * This class provides a JSON array iterator that dereferences as an instance of
+ * RapidJsonAdapter representing a value stored in the array. It has been
+ * implemented using the std::iterator template.
+ *
+ * @see RapidJsonArray
+ */
+template<class ValueType>
+class GenericRapidJsonArrayValueIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,                 // bi-directional iterator
+        GenericRapidJsonAdapter<ValueType> >             // value type
+{
+public:
+
+    /**
+     * @brief   Construct a new GenericRapidJsonArrayValueIterator using an
+     *          existing RapidJson iterator.
+     *
+     * @param   itr  RapidJson iterator to store
+     */
+    GenericRapidJsonArrayValueIterator(
+        const typename ValueType::ConstValueIterator &itr)
+      : itr(itr) { }
+
+    /// Returns a GenericRapidJsonAdapter that contains the value of the current
+    /// element.
+    GenericRapidJsonAdapter<ValueType> operator*() const
+    {
+        return GenericRapidJsonAdapter<ValueType>(*itr);
+    }
+
+    /// Returns a proxy for the value of the current element
+    DerefProxy<GenericRapidJsonAdapter<ValueType> > operator->() const
+    {
+        return DerefProxy<GenericRapidJsonAdapter<ValueType> >(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator against another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  iterator to compare against
+     *
+     * @returns true if the iterators are equal, false otherwise.
+     */
+    bool operator==(const GenericRapidJsonArrayValueIterator<ValueType> &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const GenericRapidJsonArrayValueIterator<ValueType>& other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    GenericRapidJsonArrayValueIterator<ValueType>& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    GenericRapidJsonArrayValueIterator<ValueType> operator++(int) {
+        GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    GenericRapidJsonArrayValueIterator<ValueType>& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    void advance(std::ptrdiff_t n)
+    {
+        itr += n;
+    }
+
+    std::ptrdiff_t difference(const GenericRapidJsonArrayValueIterator<ValueType> &other)
+    {
+        return std::distance(itr, other.itr);
+    }
+
+private:
+
+    typename ValueType::ConstValueIterator itr;
+};
+
+/**
+ * @brief   Class for iterating over the members belonging to a JSON object.
+ *
+ * This class provides a JSON object iterator that dereferences as an instance
+ * of GenericRapidJsonObjectMember representing one of the members of the
+ * object. It has been implemented using the std::iterator template.
+ *
+ * @see GenericRapidJsonObject
+ * @see GenericRapidJsonObjectMember
+ */
+template<class ValueType>
+class GenericRapidJsonObjectMemberIterator:
+    public std::iterator<
+        std::bidirectional_iterator_tag,                 // bi-directional iterator
+        GenericRapidJsonObjectMember<ValueType> >        // value type
+{
+public:
+
+    /**
+     * @brief   Construct an iterator from a RapidJson iterator.
+     *
+     * @param   itr  RapidJson iterator to store
+     */
+    GenericRapidJsonObjectMemberIterator(
+        const typename ValueType::ConstMemberIterator &itr)
+      : itr(itr) { }
+
+
+    /**
+     * @brief   Returns a GenericRapidJsonObjectMember that contains the key and
+     *          value belonging to the object member identified by the iterator.
+     */
+    GenericRapidJsonObjectMember<ValueType> operator*() const
+    {
+        return GenericRapidJsonObjectMember<ValueType>(
+            std::string(itr->name.GetString(), itr->name.GetStringLength()),
+            itr->value);
+    }
+
+    /// Returns a proxy for the value of the current element
+    DerefProxy<GenericRapidJsonObjectMember<ValueType> > operator->() const
+    {
+        return DerefProxy<GenericRapidJsonObjectMember<ValueType> >(**this);
+    }
+
+    /**
+     * @brief   Compare this iterator with another iterator.
+     *
+     * Note that this directly compares the iterators, not the underlying
+     * values, and assumes that two identical iterators will point to the same
+     * underlying object.
+     *
+     * @param   other  Iterator to compare with
+     *
+     * @returns true if the underlying iterators are equal, false otherwise
+     */
+    bool operator==(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
+    {
+        return itr == other.itr;
+    }
+
+    bool operator!=(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
+    {
+        return !(itr == other.itr);
+    }
+
+    GenericRapidJsonObjectMemberIterator<ValueType>& operator++()
+    {
+        itr++;
+
+        return *this;
+    }
+
+    GenericRapidJsonObjectMemberIterator<ValueType> operator++(int)
+    {
+        GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(itr);
+        ++(*this);
+        return iterator_pre;
+    }
+
+    GenericRapidJsonObjectMemberIterator<ValueType>& operator--()
+    {
+        itr--;
+
+        return *this;
+    }
+
+    std::ptrdiff_t difference(const GenericRapidJsonObjectMemberIterator &other)
+    {
+        return std::distance(itr, other.itr);
+    }
+
+private:
+
+    /// Iternal copy of the original RapidJson iterator
+    typename ValueType::ConstMemberIterator itr;
+};
+
+template<class ValueType>
+inline bool GenericRapidJsonFrozenValue<ValueType>::equalTo(
+        const Adapter &other, bool strict) const
+{
+    return GenericRapidJsonAdapter<ValueType>(value).equalTo(other, strict);
+}
+
+template<class ValueType>
+inline typename GenericRapidJsonArray<ValueType>::iterator
+        GenericRapidJsonArray<ValueType>::begin() const
+{
+    return value.Begin();
+}
+
+template<class ValueType>
+inline typename GenericRapidJsonArray<ValueType>::iterator
+        GenericRapidJsonArray<ValueType>::end() const
+{
+    return value.End();
+}
+
+template<class ValueType>
+inline typename GenericRapidJsonObject<ValueType>::iterator
+        GenericRapidJsonObject<ValueType>::begin() const
+{
+    return value.MemberBegin();
+}
+
+template<class ValueType>
+inline typename GenericRapidJsonObject<ValueType>::iterator
+        GenericRapidJsonObject<ValueType>::end() const
+{
+    return value.MemberEnd();
+}
+
+template<class ValueType>
+inline typename GenericRapidJsonObject<ValueType>::iterator
+        GenericRapidJsonObject<ValueType>::find(
+                const std::string &propertyName) const
+{
+    // Hack to support older versions of rapidjson where pointers are used as
+    // the built in iterator type. In those versions, the FindMember function
+    // would return a null pointer when the requested member could not be
+    // found. After calling FindMember on an empty object, we compare the
+    // result against what we would expect if a non-null-pointer iterator was
+    // returned.
+    const ValueType empty(rapidjson::kObjectType);
+    const typename ValueType::ConstMemberIterator maybeEnd = empty.FindMember("");
+    if (maybeEnd != empty.MemberBegin() + 1) {
+        // In addition to the pointer-based iterator issue, RapidJson's internal
+        // string comparison code seemed to rely on the query string being
+        // initialised to a length greater than or equal to that of the
+        // properties being compared. We get around this by implementing our
+        // own linear scan.
+        const size_t propertyNameLength = propertyName.length();
+        for (typename ValueType::ConstMemberIterator itr = value.MemberBegin();
+                itr != value.MemberEnd(); ++itr) {
+            const size_t memberNameLength = itr->name.GetStringLength();
+            if (memberNameLength == propertyNameLength &&
+                    strncmp(itr->name.GetString(), propertyName.c_str(),
+                        itr->name.GetStringLength()) == 0) {
+                return itr;
+            }
+        }
+
+        return value.MemberEnd();
+    }
+
+    return value.FindMember(propertyName.c_str());      // Times are good.
+}
+
+typedef GenericRapidJsonAdapter<> RapidJsonAdapter;
+typedef GenericRapidJsonArray<> RapidJsonArray;
+typedef GenericRapidJsonArrayValueIterator<> RapidJsonArrayValue;
+typedef GenericRapidJsonFrozenValue<> RapidJsonFrozenValue;
+typedef GenericRapidJsonObject<> RapidJsonObject;
+typedef GenericRapidJsonObjectMember<> RapidJsonObjectMember;
+typedef GenericRapidJsonObjectMemberIterator<> RapidJsonObjectMemberIterator;
+typedef GenericRapidJsonValue<> RapidJsonValue;
+
+/**
+ * @brief  Specialisation of the AdapterTraits template struct for a
+ *         RapidJsonAdapter that uses a pool allocator
+ */
+template<>
+struct AdapterTraits<valijson::adapters::RapidJsonAdapter>
+{
+    typedef rapidjson::Document DocumentType;
+
+    static std::string adapterName()
+    {
+        return "RapidJsonAdapter";
+    }
+};
+
+typedef rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>
+        RapidJsonCrt;
+
+/**
+ * @brief  Specialisation of the AdapterTraits template struct for a
+ *         RapidJsonAdapter that uses the default CRT allocator
+ */
+template<>
+struct AdapterTraits<valijson::adapters::GenericRapidJsonAdapter<RapidJsonCrt> >
+{
+    typedef rapidjson::GenericDocument<rapidjson::UTF8<>,
+        rapidjson::CrtAllocator> DocumentType;
+
+    static std::string adapterName()
+    {
+        return "GenericRapidJsonAdapter (using CrtAllocator)";
+    }
+};
+
+}  // namespace adapters
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/constraint_builder.hpp b/examples/validator/valijson/include/valijson/constraint_builder.hpp
new file mode 100644
index 0000000..7b1ab79
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/constraint_builder.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#ifndef __VALIJSON_CONSTRAINT_BUILDER_HPP
+#define __VALIJSON_CONSTRAINT_BUILDER_HPP
+
+namespace valijson {
+
+namespace adapters {
+    class Adapter;
+}
+
+namespace constraints {
+    struct Constraint;
+}
+
+class ConstraintBuilder
+{
+public:
+    virtual ~ConstraintBuilder() {}
+
+    virtual constraints::Constraint * make(const adapters::Adapter &) const = 0;
+};
+
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/constraints/basic_constraint.hpp b/examples/validator/valijson/include/valijson/constraints/basic_constraint.hpp
new file mode 100644
index 0000000..d086684
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/constraints/basic_constraint.hpp
@@ -0,0 +1,69 @@
+#pragma once
+#ifndef __VALIJSON_CONSTRAINTS_BASIC_CONSTRAINT_HPP
+#define __VALIJSON_CONSTRAINTS_BASIC_CONSTRAINT_HPP
+
+#include <valijson/constraints/constraint.hpp>
+#include <valijson/constraints/constraint_visitor.hpp>
+
+#include <valijson/internal/custom_allocator.hpp>
+
+namespace valijson {
+namespace constraints {
+
+/**
+ * @brief   Template class that implements the accept() and clone() functions of
+ *          the Constraint interface.
+ *
+ * @tparam  ConstraintType   name of the concrete constraint type, which must
+ *                           provide a copy constructor.
+ */
+template<typename ConstraintType>
+struct BasicConstraint: Constraint
+{
+    typedef internal::CustomAllocator<void *> Allocator;
+
+    typedef std::basic_string<char, std::char_traits<char>,
+            internal::CustomAllocator<char> > String;
+
+    BasicConstraint()
+      : allocator() { }
+
+    BasicConstraint(Allocator::CustomAlloc allocFn, Allocator::CustomFree freeFn)
+      : allocator(allocFn, freeFn) { }
+
+    BasicConstraint(const BasicConstraint &other)
+      : allocator(other.allocator) { }
+
+    virtual ~BasicConstraint<ConstraintType>() { }
+
+    virtual bool accept(ConstraintVisitor &visitor) const
+    {
+        return visitor.visit(*static_cast<const ConstraintType*>(this));
+    }
+
+    virtual Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const
+    {
+        void *ptr = allocFn(sizeof(ConstraintType));
+        if (!ptr) {
+            throw std::runtime_error(
+                    "Failed to allocate memory for cloned constraint");
+        }
+
+        try {
+            return new (ptr) ConstraintType(
+                    *static_cast<const ConstraintType*>(this));
+        } catch (...) {
+            freeFn(ptr);
+            throw;
+        }
+    }
+
+protected:
+
+    Allocator allocator;
+};
+
+} // namespace constraints
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/constraints/concrete_constraints.hpp b/examples/validator/valijson/include/valijson/constraints/concrete_constraints.hpp
new file mode 100644
index 0000000..ba0149d
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/constraints/concrete_constraints.hpp
@@ -0,0 +1,1097 @@
+/**
+ * @file
+ *
+ * @brief   Class definitions to support JSON Schema constraints
+ *
+ * This file contains class definitions for all of the constraints required to
+ * support JSON Schema. These classes all inherit from the BasicConstraint
+ * template class, which implements the common parts of the Constraint
+ * interface.
+ *
+ * @see BasicConstraint
+ * @see Constraint
+ */
+
+#pragma once
+#ifndef __VALIJSON_CONSTRAINTS_CONCRETE_CONSTRAINTS_HPP
+#define __VALIJSON_CONSTRAINTS_CONCRETE_CONSTRAINTS_HPP
+
+#include <limits>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <valijson/adapters/frozen_value.hpp>
+#include <valijson/constraints/basic_constraint.hpp>
+#include <valijson/internal/custom_allocator.hpp>
+#include <valijson/schema.hpp>
+
+namespace valijson {
+class ValidationResults;
+namespace constraints {
+
+/**
+ * @brief  Represents an 'allOf' constraint.
+ *
+ * An allOf constraint provides a collection of sub-schemas that a value must
+ * validate against. If a value fails to validate against any of these sub-
+ * schemas, then validation fails.
+ */
+class AllOfConstraint: public BasicConstraint<AllOfConstraint>
+{
+public:
+    AllOfConstraint()
+      : subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    AllOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    void addSubschema(const Subschema *subschema)
+    {
+        subschemas.push_back(subschema);
+    }
+
+    template<typename FunctorType>
+    void applyToSubschemas(const FunctorType &fn) const
+    {
+        unsigned int index = 0;
+        for (const Subschema *subschema : subschemas) {
+            if (!fn(index, subschema)) {
+                return;
+            }
+
+            index++;
+        }
+    }
+
+private:
+    typedef std::vector<const Subschema *,
+            internal::CustomAllocator<const Subschema *> > Subschemas;
+
+    /// Collection of sub-schemas, all of which must be satisfied
+    Subschemas subschemas;
+};
+
+/**
+ * @brief  Represents an 'anyOf' constraint
+ *
+ * An anyOf constraint provides a collection of sub-schemas that a value can
+ * validate against. If a value validates against one of these sub-schemas,
+ * then the validation passes.
+ */
+class AnyOfConstraint: public BasicConstraint<AnyOfConstraint>
+{
+public:
+    AnyOfConstraint()
+      : subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    AnyOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    void addSubschema(const Subschema *subschema)
+    {
+        subschemas.push_back(subschema);
+    }
+
+    template<typename FunctorType>
+    void applyToSubschemas(const FunctorType &fn) const
+    {
+        unsigned int index = 0;
+        for (const Subschema *subschema : subschemas) {
+            if (!fn(index, subschema)) {
+                return;
+            }
+
+            index++;
+        }
+    }
+
+private:
+    typedef std::vector<const Subschema *,
+            internal::CustomAllocator<const Subschema *> > Subschemas;
+
+    /// Collection of sub-schemas, at least one of which must be satisfied
+    Subschemas subschemas;
+};
+
+/**
+ * @brief  Represents a 'dependencies' constraint.
+ *
+ * A dependency constraint ensures that a given property is valid only if the
+ * properties that it depends on are present.
+ */
+class DependenciesConstraint: public BasicConstraint<DependenciesConstraint>
+{
+public:
+    DependenciesConstraint()
+      : propertyDependencies(std::less<String>(), allocator),
+        schemaDependencies(std::less<String>(), allocator)
+    { }
+
+    DependenciesConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        propertyDependencies(std::less<String>(), allocator),
+        schemaDependencies(std::less<String>(), allocator)
+    { }
+
+    template<typename StringType>
+    DependenciesConstraint & addPropertyDependency(
+            const StringType &propertyName,
+            const StringType &dependencyName)
+    {
+        const String key(propertyName.c_str(), allocator);
+        PropertyDependencies::iterator itr = propertyDependencies.find(key);
+        if (itr == propertyDependencies.end()) {
+            itr = propertyDependencies.insert(PropertyDependencies::value_type(
+                    key, PropertySet(std::less<String>(), allocator))).first;
+        }
+
+        itr->second.insert(String(dependencyName.c_str(), allocator));
+
+        return *this;
+    }
+
+    template<typename StringType, typename ContainerType>
+    DependenciesConstraint & addPropertyDependencies(
+            const StringType &propertyName,
+            const ContainerType &dependencyNames)
+    {
+        const String key(propertyName.c_str(), allocator);
+        PropertyDependencies::iterator itr = propertyDependencies.find(key);
+        if (itr == propertyDependencies.end()) {
+            itr = propertyDependencies.insert(PropertyDependencies::value_type(
+                    key, PropertySet(std::less<String>(), allocator))).first;
+        }
+
+        typedef typename ContainerType::value_type ValueType;
+        for (const ValueType &dependencyName : dependencyNames) {
+            itr->second.insert(String(dependencyName.c_str(), allocator));
+        }
+
+        return *this;
+    }
+
+    template<typename StringType>
+    DependenciesConstraint & addSchemaDependency(
+            const StringType &propertyName,
+            const Subschema *schemaDependency)
+    {
+        if (schemaDependencies.insert(SchemaDependencies::value_type(
+                String(propertyName.c_str(), allocator),
+                schemaDependency)).second) {
+            return *this;
+        }
+
+        throw std::runtime_error(
+                "Dependencies constraint already contains a dependent "
+                "schema for the property '" + propertyName + "'");
+    }
+
+    template<typename FunctorType>
+    void applyToPropertyDependencies(const FunctorType &fn) const
+    {
+        for (const PropertyDependencies::value_type &v : propertyDependencies) {
+            if (!fn(v.first, v.second)) {
+                return;
+            }
+        }
+    }
+
+    template<typename FunctorType>
+    void applyToSchemaDependencies(const FunctorType &fn) const
+    {
+        for (const SchemaDependencies::value_type &v : schemaDependencies) {
+            if (!fn(v.first, v.second)) {
+                return;
+            }
+        }
+    }
+
+private:
+    typedef std::set<String, std::less<String>, internal::CustomAllocator<String> > PropertySet;
+
+    typedef std::map<String, PropertySet, std::less<String>,
+            internal::CustomAllocator<std::pair<const String, PropertySet> > > PropertyDependencies;
+
+    typedef std::map<String, const Subschema *, std::less<String>,
+            internal::CustomAllocator<std::pair<const String, const Subschema *> > >
+                SchemaDependencies;
+
+    /// Mapping from property names to their property-based dependencies
+    PropertyDependencies propertyDependencies;
+
+    /// Mapping from property names to their schema-based dependencies
+    SchemaDependencies schemaDependencies;
+};
+
+/**
+ * @brief  Represents an 'enum' constraint
+ *
+ * An enum constraint provides a collection of permissible values for a JSON
+ * node. The node will only validate against this constraint if it matches one
+ * or more of the values in the collection.
+ */
+class EnumConstraint: public BasicConstraint<EnumConstraint>
+{
+public:
+    EnumConstraint()
+      : enumValues(Allocator::rebind<const EnumValue *>::other(allocator)) { }
+
+    EnumConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        enumValues(Allocator::rebind<const EnumValue *>::other(allocator)) { }
+
+    EnumConstraint(const EnumConstraint &other)
+      : BasicConstraint(other),
+        enumValues(Allocator::rebind<const EnumValue *>::other(allocator))
+    {
+        try {
+            // Clone individual enum values
+            for (const EnumValue *otherValue : other.enumValues) {
+                const EnumValue *value = otherValue->clone();
+                try {
+                    enumValues.push_back(value);
+                } catch (...) {
+                    delete value;
+                    throw;
+                }
+            }
+
+        } catch (...) {
+            // Delete values already added to constraint
+            for (const EnumValue *value : enumValues) {
+                delete value;
+            }
+            throw;
+        }
+    }
+
+    virtual ~EnumConstraint()
+    {
+        for (const EnumValue *value : enumValues) {
+            delete value;
+        }
+    }
+
+    void addValue(const adapters::Adapter &value)
+    {
+        // TODO: Freeze value using custom alloc/free functions
+        enumValues.push_back(value.freeze());
+    }
+
+    void addValue(const adapters::FrozenValue &value)
+    {
+        // TODO: Clone using custom alloc/free functions
+        enumValues.push_back(value.clone());
+    }
+
+    template<typename FunctorType>
+    void applyToValues(const FunctorType &fn) const
+    {
+        for (const EnumValue *value : enumValues) {
+            if (!fn(*value)) {
+                return;
+            }
+        }
+    }
+
+private:
+    typedef adapters::FrozenValue EnumValue;
+
+    typedef std::vector<const EnumValue *,
+            internal::CustomAllocator<const EnumValue *> > EnumValues;
+
+    EnumValues enumValues;
+};
+
+/**
+ * @brief  Represents non-singular 'items' and 'additionalItems' constraints
+ *
+ * Unlike the SingularItemsConstraint class, this class represents an 'items'
+ * constraint that specifies an array of sub-schemas, which should be used to
+ * validate each item in an array, in sequence. It also represents an optional
+ * 'additionalItems' sub-schema that should be used when an array contains
+ * more values than there are sub-schemas in the 'items' constraint.
+ *
+ * The prefix 'Linear' comes from the fact that this class contains a list of
+ * sub-schemas that corresponding array items must be validated against, and
+ * this validation is performed linearly (i.e. in sequence).
+ */
+class LinearItemsConstraint: public BasicConstraint<LinearItemsConstraint>
+{
+public:
+    LinearItemsConstraint()
+      : itemSubschemas(Allocator::rebind<const Subschema *>::other(allocator)),
+        additionalItemsSubschema(NULL) { }
+
+    LinearItemsConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        itemSubschemas(Allocator::rebind<const Subschema *>::other(allocator)),
+        additionalItemsSubschema(NULL) { }
+
+    void addItemSubschema(const Subschema *subschema)
+    {
+        itemSubschemas.push_back(subschema);
+    }
+
+    template<typename FunctorType>
+    void applyToItemSubschemas(const FunctorType &fn) const
+    {
+        unsigned int index = 0;
+        for( const Subschema *subschema : itemSubschemas ) {
+            if (!fn(index, subschema)) {
+                return;
+            }
+
+            index++;
+        }
+    }
+
+    const Subschema * getAdditionalItemsSubschema() const
+    {
+        return additionalItemsSubschema;
+    }
+
+    size_t getItemSubschemaCount() const
+    {
+        return itemSubschemas.size();
+    }
+
+    void setAdditionalItemsSubschema(const Subschema *subschema)
+    {
+        additionalItemsSubschema = subschema;
+    }
+
+private:
+    typedef std::vector<const Subschema *,
+            internal::CustomAllocator<const Subschema *> > Subschemas;
+
+    Subschemas itemSubschemas;
+
+    const Subschema* additionalItemsSubschema;
+};
+
+/**
+ * @brief   Represents 'maximum' and 'exclusiveMaximum' constraints
+ */
+class MaximumConstraint: public BasicConstraint<MaximumConstraint>
+{
+public:
+    MaximumConstraint()
+      : maximum(std::numeric_limits<double>::infinity()),
+        exclusiveMaximum(false) { }
+
+    MaximumConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        maximum(std::numeric_limits<double>::infinity()),
+        exclusiveMaximum(false) { }
+
+    bool getExclusiveMaximum() const
+    {
+        return exclusiveMaximum;
+    }
+
+    void setExclusiveMaximum(bool newExclusiveMaximum)
+    {
+        exclusiveMaximum = newExclusiveMaximum;
+    }
+
+    double getMaximum() const
+    {
+        return maximum;
+    }
+
+    void setMaximum(double newMaximum)
+    {
+        maximum = newMaximum;
+    }
+
+private:
+    double maximum;
+    bool exclusiveMaximum;
+};
+
+/**
+ * @brief   Represents a 'maxItems' constraint
+ */
+class MaxItemsConstraint: public BasicConstraint<MaxItemsConstraint>
+{
+public:
+    MaxItemsConstraint()
+      : maxItems(std::numeric_limits<uint64_t>::max()) { }
+
+    MaxItemsConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        maxItems(std::numeric_limits<uint64_t>::max()) { }
+
+    uint64_t getMaxItems() const
+    {
+        return maxItems;
+    }
+
+    void setMaxItems(uint64_t newMaxItems)
+    {
+        maxItems = newMaxItems;
+    }
+
+private:
+    uint64_t maxItems;
+};
+
+/**
+ * @brief   Represents a 'maxLength' constraint
+ */
+class MaxLengthConstraint: public BasicConstraint<MaxLengthConstraint>
+{
+public:
+    MaxLengthConstraint()
+      : maxLength(std::numeric_limits<uint64_t>::max()) { }
+
+    MaxLengthConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        maxLength(std::numeric_limits<uint64_t>::max()) { }
+
+    uint64_t getMaxLength() const
+    {
+        return maxLength;
+    }
+
+    void setMaxLength(uint64_t newMaxLength)
+    {
+        maxLength = newMaxLength;
+    }
+
+private:
+    uint64_t maxLength;
+};
+
+/**
+ * @brief   Represents a 'maxProperties' constraint
+ */
+class MaxPropertiesConstraint: public BasicConstraint<MaxPropertiesConstraint>
+{
+public:
+    MaxPropertiesConstraint()
+      : maxProperties(std::numeric_limits<uint64_t>::max()) { }
+
+    MaxPropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        maxProperties(std::numeric_limits<uint64_t>::max()) { }
+
+    uint64_t getMaxProperties() const
+    {
+        return maxProperties;
+    }
+
+    void setMaxProperties(uint64_t newMaxProperties)
+    {
+        maxProperties = newMaxProperties;
+    }
+
+private:
+    uint64_t maxProperties;
+};
+
+/**
+ * @brief   Represents 'minimum' and 'exclusiveMinimum' constraints
+ */
+class MinimumConstraint: public BasicConstraint<MinimumConstraint>
+{
+public:
+    MinimumConstraint()
+      : minimum(-std::numeric_limits<double>::infinity()),
+        exclusiveMinimum(false) { }
+
+    MinimumConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        minimum(-std::numeric_limits<double>::infinity()),
+        exclusiveMinimum(false) { }
+
+    bool getExclusiveMinimum() const
+    {
+        return exclusiveMinimum;
+    }
+
+    void setExclusiveMinimum(bool newExclusiveMinimum)
+    {
+        exclusiveMinimum = newExclusiveMinimum;
+    }
+
+    double getMinimum() const
+    {
+        return minimum;
+    }
+
+    void setMinimum(double newMinimum)
+    {
+        minimum = newMinimum;
+    }
+
+private:
+    double minimum;
+    bool exclusiveMinimum;
+};
+
+/**
+ * @brief   Represents a 'minItems' constraint
+ */
+class MinItemsConstraint: public BasicConstraint<MinItemsConstraint>
+{
+public:
+    MinItemsConstraint()
+      : minItems(0) { }
+
+    MinItemsConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        minItems(0) { }
+
+    uint64_t getMinItems() const
+    {
+        return minItems;
+    }
+
+    void setMinItems(uint64_t newMinItems)
+    {
+        minItems = newMinItems;
+    }
+
+private:
+    size_t minItems;
+};
+
+/**
+ * @brief   Represents a 'minLength' constraint
+ */
+class MinLengthConstraint: public BasicConstraint<MinLengthConstraint>
+{
+public:
+    MinLengthConstraint()
+      : minLength(0) { }
+
+    MinLengthConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        minLength(0) { }
+
+    int64_t getMinLength() const
+    {
+        return minLength;
+    }
+
+    void setMinLength(uint64_t newMinLength)
+    {
+        minLength = newMinLength;
+    }
+
+private:
+    uint64_t minLength;
+};
+
+/**
+ * @brief   Represents a 'minProperties' constraint
+ */
+class MinPropertiesConstraint: public BasicConstraint<MinPropertiesConstraint>
+{
+public:
+    MinPropertiesConstraint()
+      : minProperties(0) { }
+
+    MinPropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        minProperties(0) { }
+
+    uint64_t getMinProperties() const
+    {
+        return minProperties;
+    }
+
+    void setMinProperties(uint64_t newMinProperties)
+    {
+        minProperties = newMinProperties;
+    }
+
+private:
+    size_t minProperties;
+};
+
+/**
+ * @brief  Represents either 'multipleOf' or 'divisibleBy' constraints where
+ *         the divisor is a floating point number
+ */
+class MultipleOfDoubleConstraint:
+        public BasicConstraint<MultipleOfDoubleConstraint>
+{
+public:
+    MultipleOfDoubleConstraint()
+      : value(1.) { }
+
+    MultipleOfDoubleConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        value(1.) { }
+
+    double getDivisor() const
+    {
+        return value;
+    }
+
+    void setDivisor(double newValue)
+    {
+        value = newValue;
+    }
+
+private:
+    double value;
+};
+
+/**
+ * @brief  Represents either 'multipleOf' or 'divisibleBy' constraints where
+ *         the divisor is of integer type
+ */
+class MultipleOfIntConstraint:
+        public BasicConstraint<MultipleOfIntConstraint>
+{
+public:
+    MultipleOfIntConstraint()
+      : value(1) { }
+
+    MultipleOfIntConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        value(1) { }
+
+    int64_t getDivisor() const
+    {
+        return value;
+    }
+
+    void setDivisor(int64_t newValue)
+    {
+        value = newValue;
+    }
+
+private:
+    int64_t value;
+};
+
+/**
+ * @brief   Represents a 'not' constraint
+ */
+class NotConstraint: public BasicConstraint<NotConstraint>
+{
+public:
+    NotConstraint()
+      : subschema(NULL) { }
+
+    NotConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        subschema(NULL) { }
+
+    const Subschema * getSubschema() const
+    {
+        return subschema;
+    }
+
+    void setSubschema(const Subschema *subschema)
+    {
+        this->subschema = subschema;
+    }
+
+private:
+    const Subschema *subschema;
+};
+
+/**
+ * @brief   Represents a 'oneOf' constraint.
+ */
+class OneOfConstraint: public BasicConstraint<OneOfConstraint>
+{
+public:
+    OneOfConstraint()
+      : subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    OneOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    void addSubschema(const Subschema *subschema)
+    {
+        subschemas.push_back(subschema);
+    }
+
+    template<typename FunctorType>
+    void applyToSubschemas(const FunctorType &fn) const
+    {
+        unsigned int index = 0;
+        for( const Subschema *subschema : subschemas ) {
+            if (!fn(index, subschema)) {
+                return;
+            }
+
+            index++;
+        }
+    }
+
+private:
+    typedef std::vector<const Subschema *,
+            internal::CustomAllocator<const Subschema *> > Subschemas;
+
+    /// Collection of sub-schemas, exactly one of which must be satisfied
+    Subschemas subschemas;
+};
+
+/**
+ * @brief   Represents a 'pattern' constraint
+ */
+class PatternConstraint: public BasicConstraint<PatternConstraint>
+{
+public:
+    PatternConstraint()
+      : pattern(Allocator::rebind<char>::other(allocator)) { }
+
+    PatternConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        pattern(Allocator::rebind<char>::other(allocator)) { }
+
+    template<typename AllocatorType>
+    bool getPattern(std::basic_string<char, std::char_traits<char>,
+            AllocatorType> &result) const
+    {
+        result.assign(this->pattern.c_str());
+        return true;
+    }
+
+    template<typename AllocatorType>
+    std::basic_string<char, std::char_traits<char>, AllocatorType> getPattern(
+            const AllocatorType &alloc = AllocatorType()) const
+    {
+        return std::basic_string<char, std::char_traits<char>, AllocatorType>(
+                pattern.c_str(), alloc);
+    }
+
+    template<typename AllocatorType>
+    void setPattern(const std::basic_string<char, std::char_traits<char>,
+            AllocatorType> &pattern)
+    {
+        this->pattern.assign(pattern.c_str());
+    }
+
+private:
+    String pattern;
+};
+
+class PolyConstraint : public Constraint
+{
+public:
+    virtual bool accept(ConstraintVisitor &visitor) const
+    {
+        return visitor.visit(*static_cast<const PolyConstraint*>(this));
+    }
+
+    virtual Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const
+    {
+        void *ptr = allocFn(sizeOf());
+        if (!ptr) {
+            throw std::runtime_error(
+                    "Failed to allocate memory for cloned constraint");
+        }
+
+        try {
+            return cloneInto(ptr);
+        } catch (...) {
+            freeFn(ptr);
+            throw;
+        }
+    }
+
+    virtual bool validate(const adapters::Adapter &target,
+            const std::vector<std::string>& context,
+            valijson::ValidationResults *results) const = 0;
+
+private:
+    virtual Constraint * cloneInto(void *) const = 0;
+
+    virtual size_t sizeOf() const = 0;
+};
+
+/**
+ * @brief   Represents a combination of 'properties', 'patternProperties' and
+ *          'additionalProperties' constraints
+ */
+class PropertiesConstraint: public BasicConstraint<PropertiesConstraint>
+{
+public:
+    PropertiesConstraint()
+      : properties(std::less<String>(), allocator),
+        patternProperties(std::less<String>(), allocator),
+        additionalProperties(NULL) { }
+
+    PropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        properties(std::less<String>(), allocator),
+        patternProperties(std::less<String>(), allocator),
+        additionalProperties(NULL) { }
+
+    bool addPatternPropertySubschema(const char *patternProperty,
+            const Subschema *subschema)
+    {
+        return patternProperties.insert(PropertySchemaMap::value_type(
+                String(patternProperty, allocator), subschema)).second;
+    }
+
+    template<typename AllocatorType>
+    bool addPatternPropertySubschema(const std::basic_string<char,
+            std::char_traits<char>, AllocatorType> &patternProperty,
+            const Subschema *subschema)
+    {
+        return addPatternPropertySubschema(patternProperty.c_str(), subschema);
+    }
+
+    bool addPropertySubschema(const char *propertyName,
+            const Subschema *subschema)
+    {
+        return properties.insert(PropertySchemaMap::value_type(
+                String(propertyName, allocator), subschema)).second;
+    }
+
+    template<typename AllocatorType>
+    bool addPropertySubschema(const std::basic_string<char,
+            std::char_traits<char>, AllocatorType> &propertyName,
+            const Subschema *subschema)
+    {
+        return addPropertySubschema(propertyName.c_str(), subschema);
+    }
+
+    template<typename FunctorType>
+    void applyToPatternProperties(const FunctorType &fn) const
+    {
+        typedef typename PropertySchemaMap::value_type ValueType;
+        for( const ValueType &value : patternProperties ) {
+            if (!fn(value.first, value.second)) {
+                return;
+            }
+        }
+    }
+
+    template<typename FunctorType>
+    void applyToProperties(const FunctorType &fn) const
+    {
+        typedef typename PropertySchemaMap::value_type ValueType;
+        for( const ValueType &value : properties ) {
+            if (!fn(value.first, value.second)) {
+                return;
+            }
+        }
+    }
+
+    const Subschema * getAdditionalPropertiesSubschema() const
+    {
+        return additionalProperties;
+    }
+
+    void setAdditionalPropertiesSubschema(const Subschema *subschema)
+    {
+        additionalProperties = subschema;
+    }
+
+private:
+    typedef std::map<String, const Subschema *, std::less<String>, internal::CustomAllocator<std::pair<const String, const Subschema *> > >
+            PropertySchemaMap;
+
+    PropertySchemaMap properties;
+    PropertySchemaMap patternProperties;
+
+    const Subschema *additionalProperties;
+};
+
+/**
+ * @brief   Represents a 'required' constraint
+ */
+class RequiredConstraint: public BasicConstraint<RequiredConstraint>
+{
+public:
+    RequiredConstraint()
+      : requiredProperties(std::less<String>(), allocator) { }
+
+    RequiredConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        requiredProperties(std::less<String>(), allocator) { }
+
+    bool addRequiredProperty(const char *propertyName)
+    {
+        return requiredProperties.insert(String(propertyName,
+                Allocator::rebind<char>::other(allocator))).second;
+    }
+
+    template<typename AllocatorType>
+    bool addRequiredProperty(const std::basic_string<char,
+            std::char_traits<char>, AllocatorType> &propertyName)
+    {
+        return addRequiredProperty(propertyName.c_str());
+    }
+
+    template<typename FunctorType>
+    void applyToRequiredProperties(const FunctorType &fn) const
+    {
+        for( const String &propertyName : requiredProperties ) {
+            if (!fn(propertyName)) {
+                return;
+            }
+        }
+    }
+
+private:
+    typedef std::set<String, std::less<String>,
+            internal::CustomAllocator<String> > RequiredProperties;
+
+    RequiredProperties requiredProperties;
+};
+
+/**
+ * @brief  Represents an 'items' constraint that specifies one sub-schema
+ *
+ * A value is considered valid against this constraint if it is an array, and
+ * each item in the array validates against the sub-schema specified by this
+ * constraint.
+ *
+ * The prefix 'Singular' comes from the fact that array items must validate
+ * against exactly one sub-schema.
+ */
+class SingularItemsConstraint: public BasicConstraint<SingularItemsConstraint>
+{
+public:
+    SingularItemsConstraint()
+      : itemsSubschema(NULL) { }
+
+    SingularItemsConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        itemsSubschema(NULL) { }
+
+    const Subschema * getItemsSubschema() const
+    {
+        return itemsSubschema;
+    }
+
+    void setItemsSubschema(const Subschema *subschema)
+    {
+        itemsSubschema = subschema;
+    }
+
+private:
+    const Subschema *itemsSubschema;
+};
+
+/**
+ * @brief   Represents a 'type' constraint.
+ */
+class TypeConstraint: public BasicConstraint<TypeConstraint>
+{
+public:
+    enum JsonType {
+        kAny,
+        kArray,
+        kBoolean,
+        kInteger,
+        kNull,
+        kNumber,
+        kObject,
+        kString
+    };
+
+    TypeConstraint()
+      : namedTypes(std::less<JsonType>(), allocator),
+        schemaTypes(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    TypeConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn),
+        namedTypes(std::less<JsonType>(), allocator),
+        schemaTypes(Allocator::rebind<const Subschema *>::other(allocator)) { }
+
+    void addNamedType(JsonType type)
+    {
+        namedTypes.insert(type);
+    }
+
+    void addSchemaType(const Subschema *subschema)
+    {
+        schemaTypes.push_back(subschema);
+    }
+
+    template<typename FunctorType>
+    void applyToNamedTypes(const FunctorType &fn) const
+    {
+        for( const JsonType namedType : namedTypes ) {
+            if (!fn(namedType)) {
+                return;
+            }
+        }
+    }
+
+    template<typename FunctorType>
+    void applyToSchemaTypes(const FunctorType &fn) const
+    {
+        unsigned int index = 0;
+        for( const Subschema *subschema : schemaTypes ) {
+            if (!fn(index, subschema)) {
+                return;
+            }
+
+            index++;
+        }
+    }
+
+    template<typename AllocatorType>
+    static JsonType jsonTypeFromString(const std::basic_string<char,
+            std::char_traits<char>, AllocatorType> &typeName)
+    {
+        if (typeName.compare("any") == 0) {
+            return kAny;
+        } else if (typeName.compare("array") == 0) {
+            return kArray;
+        } else if (typeName.compare("boolean") == 0) {
+            return kBoolean;
+        } else if (typeName.compare("integer") == 0) {
+            return kInteger;
+        } else if (typeName.compare("null") == 0) {
+            return kNull;
+        } else if (typeName.compare("number") == 0) {
+            return kNumber;
+        } else if (typeName.compare("object") == 0) {
+            return kObject;
+        } else if (typeName.compare("string") == 0) {
+            return kString;
+        }
+
+        throw std::runtime_error("Unrecognised JSON type name '" +
+                std::string(typeName.c_str()) + "'");
+    }
+
+private:
+    typedef std::set<JsonType, std::less<JsonType>, internal::CustomAllocator<JsonType> > NamedTypes;
+
+    typedef std::vector<const Subschema *,
+            Allocator::rebind<const Subschema *>::other> SchemaTypes;
+
+    /// Set of named JSON types that serve as valid types
+    NamedTypes namedTypes;
+
+    /// Set of sub-schemas that serve as valid types
+    SchemaTypes schemaTypes;
+};
+
+/**
+ * @brief   Represents a 'uniqueItems' constraint
+ */
+class UniqueItemsConstraint: public BasicConstraint<UniqueItemsConstraint>
+{
+public:
+    UniqueItemsConstraint() { }
+
+    UniqueItemsConstraint(CustomAlloc allocFn, CustomFree freeFn)
+      : BasicConstraint(allocFn, freeFn) { }
+};
+
+} // namespace constraints
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/constraints/constraint.hpp b/examples/validator/valijson/include/valijson/constraints/constraint.hpp
new file mode 100644
index 0000000..c053dbb
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/constraints/constraint.hpp
@@ -0,0 +1,54 @@
+#pragma once
+#ifndef __VALIJSON_CONSTRAINTS_CONSTRAINT_HPP
+#define __VALIJSON_CONSTRAINTS_CONSTRAINT_HPP
+
+namespace valijson {
+namespace constraints {
+
+class ConstraintVisitor;
+
+/**
+ * @brief  Interface that must be implemented by concrete constraint types.
+ *
+ * @todo  Consider using something like the boost::cloneable concept here.
+ */
+struct Constraint
+{
+    /// Typedef for custom new-/malloc-like function
+    typedef void * (*CustomAlloc)(size_t size);
+
+    /// Typedef for custom free-like function
+    typedef void (*CustomFree)(void *);
+
+    /**
+     * @brief  Virtual destructor.
+     */
+    virtual ~Constraint() { }
+
+    /**
+     * @brief  Perform an action on the constraint using the visitor pattern.
+     *
+     * Note that Constraints cannot be modified by visitors.
+     *
+     * @param  visitor  Reference to a ConstraintVisitor object.
+     *
+     * @returns  the boolean value returned by one of the visitor's visit
+     *           functions.
+     */
+    virtual bool accept(ConstraintVisitor &visitor) const = 0;
+
+    /**
+     * @brief  Make a copy of a constraint.
+     *
+     * Note that this should be a deep copy of the constraint.
+     *
+     * @returns  an owning-pointer to the new constraint.
+     */
+    virtual Constraint * clone(CustomAlloc, CustomFree) const = 0;
+
+};
+
+} // namespace constraints
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/constraints/constraint_visitor.hpp b/examples/validator/valijson/include/valijson/constraints/constraint_visitor.hpp
new file mode 100644
index 0000000..a45dab0
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/constraints/constraint_visitor.hpp
@@ -0,0 +1,96 @@
+#pragma once
+#ifndef __VALIJSON_CONSTRAINTS_CONSTRAINT_VISITOR_HPP
+#define __VALIJSON_CONSTRAINTS_CONSTRAINT_VISITOR_HPP
+
+namespace valijson {
+namespace constraints {
+
+class AllOfConstraint;
+class AnyOfConstraint;
+class DependenciesConstraint;
+class EnumConstraint;
+class LinearItemsConstraint;
+class MaxItemsConstraint;
+class MaximumConstraint;
+class MaxLengthConstraint;
+class MaxPropertiesConstraint;
+class MinItemsConstraint;
+class MinimumConstraint;
+class MinLengthConstraint;
+class MinPropertiesConstraint;
+class MultipleOfDoubleConstraint;
+class MultipleOfIntConstraint;
+class NotConstraint;
+class OneOfConstraint;
+class PatternConstraint;
+class PolyConstraint;
+class PropertiesConstraint;
+class RequiredConstraint;
+class SingularItemsConstraint;
+class TypeConstraint;
+class UniqueItemsConstraint;
+
+/// Interface to allow usage of the visitor pattern with Constraints
+class ConstraintVisitor
+{
+protected:
+    virtual ~ConstraintVisitor() {}
+    
+    // Shorten type names for derived classes outside of this namespace
+    typedef constraints::AllOfConstraint AllOfConstraint;
+    typedef constraints::AnyOfConstraint AnyOfConstraint;
+    typedef constraints::DependenciesConstraint DependenciesConstraint;
+    typedef constraints::EnumConstraint EnumConstraint;
+    typedef constraints::LinearItemsConstraint LinearItemsConstraint;
+    typedef constraints::MaximumConstraint MaximumConstraint;
+    typedef constraints::MaxItemsConstraint MaxItemsConstraint;
+    typedef constraints::MaxLengthConstraint MaxLengthConstraint;
+    typedef constraints::MaxPropertiesConstraint MaxPropertiesConstraint;
+    typedef constraints::MinimumConstraint MinimumConstraint;
+    typedef constraints::MinItemsConstraint MinItemsConstraint;
+    typedef constraints::MinLengthConstraint MinLengthConstraint;
+    typedef constraints::MinPropertiesConstraint MinPropertiesConstraint;
+    typedef constraints::MultipleOfDoubleConstraint MultipleOfDoubleConstraint;
+    typedef constraints::MultipleOfIntConstraint MultipleOfIntConstraint;
+    typedef constraints::NotConstraint NotConstraint;
+    typedef constraints::OneOfConstraint OneOfConstraint;
+    typedef constraints::PatternConstraint PatternConstraint;
+    typedef constraints::PolyConstraint PolyConstraint;
+    typedef constraints::PropertiesConstraint PropertiesConstraint;
+    typedef constraints::RequiredConstraint RequiredConstraint;
+    typedef constraints::SingularItemsConstraint SingularItemsConstraint;
+    typedef constraints::TypeConstraint TypeConstraint;
+    typedef constraints::UniqueItemsConstraint UniqueItemsConstraint;
+
+public:
+
+    virtual bool visit(const AllOfConstraint &) = 0;
+    virtual bool visit(const AnyOfConstraint &) = 0;
+    virtual bool visit(const DependenciesConstraint &) = 0;
+    virtual bool visit(const EnumConstraint &) = 0;
+    virtual bool visit(const LinearItemsConstraint &) = 0;
+    virtual bool visit(const MaximumConstraint &) = 0;
+    virtual bool visit(const MaxItemsConstraint &) = 0;
+    virtual bool visit(const MaxLengthConstraint &) = 0;
+    virtual bool visit(const MaxPropertiesConstraint &) = 0;
+    virtual bool visit(const MinimumConstraint &) = 0;
+    virtual bool visit(const MinItemsConstraint &) = 0;
+    virtual bool visit(const MinLengthConstraint &) = 0;
+    virtual bool visit(const MinPropertiesConstraint &) = 0;
+    virtual bool visit(const MultipleOfDoubleConstraint &) = 0;
+    virtual bool visit(const MultipleOfIntConstraint &) = 0;
+    virtual bool visit(const NotConstraint &) = 0;
+    virtual bool visit(const OneOfConstraint &) = 0;
+    virtual bool visit(const PatternConstraint &) = 0;
+    virtual bool visit(const PolyConstraint &) = 0;
+    virtual bool visit(const PropertiesConstraint &) = 0;
+    virtual bool visit(const RequiredConstraint &) = 0;
+    virtual bool visit(const SingularItemsConstraint &) = 0;
+    virtual bool visit(const TypeConstraint &) = 0;
+    virtual bool visit(const UniqueItemsConstraint &) = 0;
+};
+
+}  // namespace constraints
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/internal/custom_allocator.hpp b/examples/validator/valijson/include/valijson/internal/custom_allocator.hpp
new file mode 100644
index 0000000..062f0dd
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/internal/custom_allocator.hpp
@@ -0,0 +1,110 @@
+#ifndef __VALIJSON_CUSTOM_ALLOCATOR_HPP
+#define __VALIJSON_CUSTOM_ALLOCATOR_HPP
+
+namespace valijson {
+namespace internal {
+
+template<class T>
+class CustomAllocator
+{
+public:
+    /// Typedef for custom new-/malloc-like function
+    typedef void * (*CustomAlloc)(size_t size);
+
+    /// Typedef for custom free-like function
+    typedef void (*CustomFree)(void *);
+
+    // Standard allocator typedefs
+    typedef T value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef T& reference;
+    typedef const T& const_reference;
+    typedef std::size_t size_type;
+    typedef std::ptrdiff_t difference_type;
+
+    template<typename U>
+    struct rebind
+    {
+        typedef CustomAllocator<U> other;
+    };
+
+    CustomAllocator()
+      : allocFn(::operator new),
+        freeFn(::operator delete) { }
+
+    CustomAllocator(CustomAlloc allocFn, CustomFree freeFn)
+      : allocFn(allocFn),
+        freeFn(freeFn) { }
+
+    CustomAllocator(const CustomAllocator &other)
+      : allocFn(other.allocFn),
+        freeFn(other.freeFn) { }
+
+    template<typename U>
+    CustomAllocator(CustomAllocator<U> const &other)
+      : allocFn(other.allocFn),
+        freeFn(other.freeFn) { }
+
+    CustomAllocator & operator=(const CustomAllocator &other)
+    {
+        allocFn = other.allocFn;
+        freeFn = other.freeFn;
+
+        return *this;
+    }
+
+    pointer address(reference r)
+    {
+        return &r;
+    }
+
+    const_pointer address(const_reference r)
+    {
+        return &r;
+    }
+
+    pointer allocate(size_type cnt, const void * = 0)
+    {
+        return reinterpret_cast<pointer>(allocFn(cnt * sizeof(T)));
+    }
+
+    void deallocate(pointer p, size_type)
+    {
+        freeFn(p);
+    }
+
+    size_type max_size() const
+    {
+        return std::numeric_limits<size_type>::max() / sizeof(T);
+    }
+
+    void construct(pointer p, const T& t)
+    {
+        new(p) T(t);
+    }
+
+    void destroy(pointer p)
+    {
+        p->~T();
+    }
+
+    bool operator==(const CustomAllocator &other) const
+    {
+        return other.allocFn == allocFn && other.freeFn == freeFn;
+    }
+
+    bool operator!=(const CustomAllocator &other) const
+    {
+        return !operator==(other);
+    }
+
+    CustomAlloc allocFn;
+
+    CustomFree freeFn;
+};
+
+} // end namespace internal
+} // end namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/internal/debug.hpp b/examples/validator/valijson/include/valijson/internal/debug.hpp
new file mode 100644
index 0000000..0be7f4a
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/internal/debug.hpp
@@ -0,0 +1,33 @@
+#ifndef __VALIJSON_DEBUG_HPP
+#define __VALIJSON_DEBUG_HPP
+
+#include <string>
+
+namespace valijson {
+namespace internal {
+
+template<typename AdapterType>
+std::string nodeTypeAsString(const AdapterType &node) {
+    if (node.isArray()) {
+        return "array";
+    } else if (node.isObject()) {
+        return "object";
+    } else if (node.isString()) {
+        return "string";
+    } else if (node.isNull()) {
+        return "null";
+    } else if (node.isInteger()) {
+        return "integer";
+    } else if (node.isDouble()) {
+        return "double";
+    } else if (node.isBool()) {
+        return "bool";
+    }
+
+    return "unknown";
+}
+
+} // end namespace internal
+} // end namespace valijson
+
+#endif
\ No newline at end of file
diff --git a/examples/validator/valijson/include/valijson/internal/json_pointer.hpp b/examples/validator/valijson/include/valijson/internal/json_pointer.hpp
new file mode 100644
index 0000000..2a3cb0f
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/internal/json_pointer.hpp
@@ -0,0 +1,257 @@
+#pragma once
+#ifndef __VALIJSON_INTERNAL_JSON_POINTER_HPP
+#define __VALIJSON_INTERNAL_JSON_POINTER_HPP
+
+#include <algorithm>
+#include <cerrno>
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+#include <string>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/internal/optional.hpp>
+
+namespace valijson {
+namespace internal {
+namespace json_pointer {
+
+/**
+ * @brief   Replace all occurrences of `search` with `replace`. Modifies `subject` in place
+ *
+ * @param   subject  string to operate on
+ * @param   search   string to search
+ * @param   replace  replacement string
+ */
+inline void replace_all_inplace(std::string& subject, const char* search,
+                                const char* replace)
+{
+    size_t pos = 0;
+
+    while((pos = subject.find(search, pos)) != std::string::npos) {
+        subject.replace(pos, strlen(search), replace);
+        pos += strlen(replace);
+    }
+}
+
+/**
+ * @brief   Return the char value corresponding to a 2-digit hexadecimal string
+ *
+ * @throws  std::runtime_error for strings that are not exactly two characters
+ *          in length and for strings that contain non-hexadecimal characters
+ *
+ * @return  decoded char value corresponding to the hexadecimal string
+ */
+inline char decodePercentEncodedChar(const std::string &digits)
+{
+    if (digits.length() != 2) {
+        throw std::runtime_error("Failed to decode %-encoded character '" +
+                digits + "' due to unexpected number of characters; "
+                "expected two characters");
+    }
+
+    errno = 0;
+    const char *begin = digits.c_str();
+    char *end = NULL;
+    const unsigned long value = strtoul(begin, &end, 16);
+    if (end != begin && *end != '\0') {
+        throw std::runtime_error("Failed to decode %-encoded character '" +
+                digits + "'");
+    }
+
+    return char(value);
+}
+
+/**
+ * @brief   Extract and transform the token between two iterators
+ *
+ * This function is responsible for extracting a JSON Reference token from
+ * between two iterators, and performing any necessary transformations, before
+ * returning the resulting string. Its main purpose is to replace the escaped
+ * character sequences defined in the RFC-6901 (JSON Pointer), and to decode
+ * %-encoded character sequences defined in RFC-3986 (URI).
+ *
+ * The encoding used in RFC-3986 should be familiar to many developers, but
+ * the escaped character sequences used in JSON Pointers may be less so. From
+ * the JSON Pointer specification (RFC 6901, April 2013):
+ *
+ *    Evaluation of each reference token begins by decoding any escaped
+ *    character sequence.  This is performed by first transforming any
+ *    occurrence of the sequence '~1' to '/', and then transforming any
+ *    occurrence of the sequence '~0' to '~'.  By performing the
+ *    substitutions in this order, an implementation avoids the error of
+ *    turning '~01' first into '~1' and then into '/', which would be
+ *    incorrect (the string '~01' correctly becomes '~1' after
+ *    transformation).
+ *
+ * @param   begin  iterator pointing to beginning of a token
+ * @param   end    iterator pointing to one character past the end of the token
+ *
+ * @return  string with escaped character sequences replaced
+ *
+ */
+inline std::string extractReferenceToken(std::string::const_iterator begin,
+        std::string::const_iterator end)
+{
+    std::string token(begin, end);
+
+    // Replace JSON Pointer-specific escaped character sequences
+    replace_all_inplace(token, "~1", "/");
+    replace_all_inplace(token, "~0", "~");
+
+    // Replace %-encoded character sequences with their actual characters
+    for (size_t n = token.find('%'); n != std::string::npos;
+            n = token.find('%', n + 1)) {
+
+        try {
+            const char c = decodePercentEncodedChar(token.substr(n + 1, 2));
+            token.replace(n, 3, &c, 1);
+
+        } catch (const std::runtime_error &e) {
+            throw std::runtime_error(
+                    std::string(e.what()) + "; in token: " + token);
+        }
+    }
+
+    return token;
+}
+
+/**
+ * @brief   Recursively locate the value referenced by a JSON Pointer
+ *
+ * This function takes both a string reference and an iterator to the beginning
+ * of the substring that is being resolved. This iterator is expected to point
+ * to the beginning of a reference token, whose length will be determined by
+ * searching for the next delimiter ('/' or '\0'). A reference token must be
+ * at least one character in length to be considered valid.
+ *
+ * Once the next reference token has been identified, it will be used either as
+ * an array index or as an the name an object member. The validity of a
+ * reference token depends on the type of the node currently being traversed,
+ * and the applicability of the token to that node. For example, an array can
+ * only be dereferenced by a non-negative integral index.
+ *
+ * Once the next node has been identified, the length of the remaining portion
+ * of the JSON Pointer will be used to determine whether recursion should
+ * terminate.
+ *
+ * @param   node            current node in recursive evaluation of JSON Pointer
+ * @param   jsonPointer     string containing complete JSON Pointer
+ * @param   jsonPointerItr  string iterator pointing the beginning of the next
+ *                          reference token
+ *
+ * @return  an instance of AdapterType that wraps the dereferenced node
+ */
+template<typename AdapterType>
+inline AdapterType resolveJsonPointer(
+        const AdapterType &node,
+        const std::string &jsonPointer,
+        const std::string::const_iterator jsonPointerItr)
+{
+    // TODO: This function will probably need to implement support for
+    // fetching documents referenced by JSON Pointers, similar to the
+    // populateSchema function.
+
+    const std::string::const_iterator jsonPointerEnd = jsonPointer.end();
+
+    // Terminate recursion if all reference tokens have been consumed
+    if (jsonPointerItr == jsonPointerEnd) {
+        return node;
+    }
+
+    // Reference tokens must begin with a leading slash
+    if (*jsonPointerItr != '/') {
+        throw std::runtime_error("Expected reference token to begin with "
+                "leading slash; remaining tokens: " +
+                std::string(jsonPointerItr, jsonPointerEnd));
+    }
+
+    // Find iterator that points to next slash or newline character; this is
+    // one character past the end of the current reference token
+    std::string::const_iterator jsonPointerNext =
+            std::find(jsonPointerItr + 1, jsonPointerEnd, '/');
+
+    // Extract the next reference token
+    const std::string referenceToken = extractReferenceToken(
+            jsonPointerItr + 1, jsonPointerNext);
+
+    // Empty reference tokens should be ignored
+    if (referenceToken.empty()) {
+        return resolveJsonPointer(node, jsonPointer, jsonPointerNext);
+
+    } else if (node.isArray()) {
+        if (referenceToken.compare("-") == 0) {
+            throw std::runtime_error("Hyphens cannot be used as array indices "
+                    "since the requested array element does not yet exist");
+        }
+
+        try {
+            // Fragment must be non-negative integer
+            const uint64_t index = std::stoul(referenceToken);
+            typedef typename AdapterType::Array Array;
+            typename Array::const_iterator itr = node.asArray().begin();
+
+            if (index > node.asArray().size() - 1) {
+                throw std::runtime_error("Expected reference token to identify "
+                        "an element in the current array, but array index is "
+                        "out of bounds; actual token: " + referenceToken);
+            }
+
+            if (index > static_cast<uint64_t>(std::numeric_limits<std::ptrdiff_t>::max())) {
+                throw std::runtime_error("Array index out of bounds; hard "
+                        "limit is " + std::to_string(
+                                std::numeric_limits<std::ptrdiff_t>::max()));
+            }
+
+            itr.advance(static_cast<std::ptrdiff_t>(index));
+
+            // Recursively process the remaining tokens
+            return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext);
+
+        } catch (std::invalid_argument &) {
+            throw std::runtime_error("Expected reference token to contain a "
+                    "non-negative integer to identify an element in the "
+                    "current array; actual token: " + referenceToken);
+        }
+
+    } else if (node.maybeObject()) {
+        // Fragment must identify a member of the candidate object
+        typedef typename AdapterType::Object Object;
+        typename Object::const_iterator itr = node.asObject().find(
+                referenceToken);
+        if (itr == node.asObject().end()) {
+            throw std::runtime_error("Expected reference token to identify an "
+                    "element in the current object; "
+                    "actual token: " + referenceToken);
+        }
+
+        // Recursively process the remaining tokens
+        return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext);
+    }
+
+    throw std::runtime_error("Expected end of JSON Pointer, but at least "
+            "one reference token has not been processed; remaining tokens: " +
+            std::string(jsonPointerNext, jsonPointerEnd));
+}
+
+/**
+ * @brief   Return the JSON Value referenced by a JSON Pointer
+ *
+ * @param   rootNode     node to use as root for JSON Pointer resolution
+ * @param   jsonPointer  string containing JSON Pointer
+ *
+ * @return  an instance AdapterType in the specified document
+ */
+template<typename AdapterType>
+inline AdapterType resolveJsonPointer(
+        const AdapterType &rootNode,
+        const std::string &jsonPointer)
+{
+    return resolveJsonPointer(rootNode, jsonPointer, jsonPointer.begin());
+}
+
+} // namespace json_pointer
+} // namespace internal
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/internal/json_reference.hpp b/examples/validator/valijson/include/valijson/internal/json_reference.hpp
new file mode 100644
index 0000000..592fe6b
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/internal/json_reference.hpp
@@ -0,0 +1,65 @@
+#pragma once
+#ifndef __VALIJSON_INTERNAL_JSON_REFERENCE_HPP
+#define __VALIJSON_INTERNAL_JSON_REFERENCE_HPP
+
+#include <stdexcept>
+#include <string>
+
+#include <valijson/internal/optional.hpp>
+
+namespace valijson {
+namespace internal {
+namespace json_reference {
+
+    /**
+     * @brief   Extract URI from JSON Reference relative to the current schema
+     *
+     * @param   jsonRef  JSON Reference to extract from
+     * @param   schema   Schema that JSON Reference URI is relative to
+     *
+     * @return  Optional string containing URI
+     */
+    inline opt::optional<std::string> getJsonReferenceUri(
+        const std::string &jsonRef)
+    {
+        const size_t ptrPos = jsonRef.find("#");
+        if (ptrPos == 0) {
+            // The JSON Reference does not contain a URI, but might contain a
+            // JSON Pointer that refers to the current document
+            return opt::optional<std::string>();
+        } else if (ptrPos != std::string::npos) {
+            // The JSON Reference contains a URI and possibly a JSON Pointer
+            return jsonRef.substr(0, ptrPos);
+        }
+
+        // The entire JSON Reference should be treated as a URI
+        return jsonRef;
+    }
+
+    /**
+     * @brief   Extract JSON Pointer portion of a JSON Reference
+     *
+     * @param   jsonRef  JSON Reference to extract from
+     *
+     * @return  Optional string containing JSON Pointer
+     */
+    inline opt::optional<std::string> getJsonReferencePointer(
+        const std::string &jsonRef)
+    {
+        // Attempt to extract JSON Pointer if '#' character is present. Note
+        // that a valid pointer would contain at least a leading forward
+        // slash character.
+        const size_t ptrPos = jsonRef.find("#");
+        if (ptrPos != std::string::npos) {
+            return jsonRef.substr(ptrPos + 1);
+        }
+
+        return opt::optional<std::string>();
+    }
+
+
+} // namespace json_reference
+} // namespace internal
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/internal/optional.hpp b/examples/validator/valijson/include/valijson/internal/optional.hpp
new file mode 100644
index 0000000..8ff285c
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/internal/optional.hpp
@@ -0,0 +1,18 @@
+#pragma once
+#ifndef __VALIJSON_OPTIONAL_HPP
+#define __VALIJSON_OPTIONAL_HPP
+
+#if __cplusplus >= 201703
+// Visual C++ only supports __has_include in versions 14.12 and greater
+#  if !defined(_MSC_VER) || _MSC_VER >= 1912
+#    if __has_include(<optional>)
+#      include <optional>
+namespace opt = std;
+#    endif
+#  endif
+#else
+#  include <compat/optional.hpp>
+namespace opt = std::experimental;
+#endif
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/internal/uri.hpp b/examples/validator/valijson/include/valijson/internal/uri.hpp
new file mode 100644
index 0000000..c1fe6d2
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/internal/uri.hpp
@@ -0,0 +1,37 @@
+#pragma once
+#ifndef __VALIJSON_INTERNAL_URI_HPP
+#define __VALIJSON_INTERNAL_URI_HPP
+
+#include <string>
+
+namespace valijson {
+namespace internal {
+namespace uri {
+
+    /**
+     * @brief  Placeholder function to check whether a URI is absolute
+     *
+     * This function just checks for '://'
+     */
+    inline bool isUriAbsolute(const std::string &documentUri)
+    {
+        static const char * placeholderMarker = "://";
+
+        return documentUri.find(placeholderMarker) != std::string::npos;
+    }
+
+    /**
+     * Placeholder function to resolve a relative URI within a given scope
+     */
+    inline std::string resolveRelativeUri(
+            const std::string &resolutionScope,
+            const std::string &relativeUri)
+    {
+        return resolutionScope + relativeUri;
+    }
+
+} // namespace uri
+} // namespace internal
+} // namespace valijson
+
+#endif  // __VALIJSON_INTERNAL_URI_HPP
diff --git a/examples/validator/valijson/include/valijson/schema.hpp b/examples/validator/valijson/include/valijson/schema.hpp
new file mode 100644
index 0000000..2308e36
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/schema.hpp
@@ -0,0 +1,213 @@
+#pragma once
+#ifndef __VALIJSON_SCHEMA_HPP
+#define __VALIJSON_SCHEMA_HPP
+
+#include <cstdio>
+#include <set>
+
+#include <valijson/subschema.hpp>
+
+namespace valijson {
+
+/**
+ * Represents the root of a JSON Schema
+ *
+ * The root is distinct from other sub-schemas because it is the canonical
+ * starting point for validation of a document against a given a JSON Schema.
+ */
+class Schema: public Subschema
+{
+public:
+    /**
+     * @brief  Construct a new Schema instance with no constraints
+     */
+    Schema()
+      : sharedEmptySubschema(newSubschema()) { }
+
+    /**
+     * @brief  Construct a new Schema using custom memory management
+     *         functions
+     *
+     * @param  allocFn  malloc- or new-like function to allocate memory
+     *                  within Schema, such as for Subschema instances
+     * @param  freeFn   free-like function to free memory allocated with
+     *                  the `customAlloc` function
+     */
+    Schema(CustomAlloc allocFn, CustomFree freeFn)
+      : Subschema(allocFn, freeFn),
+        sharedEmptySubschema(newSubschema()) { }
+
+    /**
+     * @brief  Clean up and free all memory managed by the Schema
+     *
+     * Note that any Subschema pointers created and returned by this Schema
+     * should be considered invalid.
+     */
+    virtual ~Schema()
+    {
+        sharedEmptySubschema->~Subschema();
+        freeFn(const_cast<Subschema *>(sharedEmptySubschema));
+        sharedEmptySubschema = NULL;
+
+        try {
+            for (std::set<Subschema *>::iterator itr = subschemaSet.begin();
+                    itr != subschemaSet.end(); ++itr) {
+                Subschema *subschema = *itr;
+                subschema->~Subschema();
+                freeFn(subschema);
+            }
+        } catch (const std::exception &e) {
+            fprintf(stderr, "Caught an exception while destroying Schema: %s",
+                    e.what());
+        }
+    }
+
+    /**
+     * @brief  Copy a constraint to a specific sub-schema
+     *
+     * @param  constraint  reference to a constraint that will be copied into
+     *                     the sub-schema
+     * @param  subschema   pointer to the sub-schema that will own the copied
+     *                     constraint
+     *
+     * @throws std::runtime_error if the sub-schema is not owned by this Schema
+     *         instance
+     */
+    void addConstraintToSubschema(const Constraint &constraint,
+            const Subschema *subschema)
+    {
+        // TODO: Check heirarchy for subschemas that do not belong...
+
+        mutableSubschema(subschema)->addConstraint(constraint);
+    }
+
+    /**
+     * @brief  Create a new Subschema instance that is owned by this Schema
+     *
+     * @returns  const pointer to the new Subschema instance
+     */
+    const Subschema * createSubschema()
+    {
+        Subschema *subschema = newSubschema();
+
+        try {
+            if (!subschemaSet.insert(subschema).second) {
+                throw std::runtime_error(
+                        "Failed to store pointer for new sub-schema");
+            }
+        } catch (...) {
+            subschema->~Subschema();
+            freeFn(subschema);
+            throw;
+        }
+
+        return subschema;
+    }
+
+    /**
+     * @brief  Return a pointer to the shared empty schema
+     */
+    const Subschema * emptySubschema() const
+    {
+        return sharedEmptySubschema;
+    }
+
+    /**
+     * @brief  Get a pointer to the root sub-schema of this Schema instance
+     */
+    const Subschema * root() const
+    {
+        return this;
+    }
+
+    /**
+     * @brief  Update the description for one of the sub-schemas owned by this
+     *         Schema instance
+     *
+     * @param  subschema    sub-schema to update
+     * @param  description  new description
+     */
+    void setSubschemaDescription(const Subschema *subschema,
+            const std::string &description)
+    {
+        mutableSubschema(subschema)->setDescription(description);
+    }
+
+    /**
+     * @brief  Update the ID for one of the sub-schemas owned by this Schema
+     *         instance
+     *
+     * @param  subschema  sub-schema to update
+     * @param  id         new ID
+     */
+    void setSubschemaId(const Subschema *subschema, const std::string &id)
+    {
+        mutableSubschema(subschema)->setId(id);
+    }
+
+    /**
+     * @brief  Update the title for one of the sub-schemas owned by this Schema
+     *         instance
+     *
+     * @param  subschema  sub-schema to update
+     * @param  title      new title
+     */
+    void setSubschemaTitle(const Subschema *subschema, const std::string &title)
+    {
+        mutableSubschema(subschema)->setTitle(title);
+    }
+
+private:
+
+    // Disable copy construction
+    Schema(const Schema &);
+
+    // Disable copy assignment
+    Schema & operator=(const Schema &);
+
+    Subschema *newSubschema()
+    {
+        void *ptr = allocFn(sizeof(Subschema));
+        if (!ptr) {
+            throw std::runtime_error(
+                    "Failed to allocate memory for shared empty sub-schema");
+        }
+
+        try {
+            return new (ptr) Subschema();
+        } catch (...) {
+            freeFn(ptr);
+            throw;
+        }
+    }
+
+    Subschema * mutableSubschema(const Subschema *subschema)
+    {
+        if (subschema == this) {
+            return this;
+        }
+
+        if (subschema == sharedEmptySubschema) {
+            throw std::runtime_error(
+                    "Cannot modify the shared empty sub-schema");
+        }
+
+        Subschema *noConst = const_cast<Subschema*>(subschema);
+        if (subschemaSet.find(noConst) == subschemaSet.end()) {
+            throw std::runtime_error(
+                    "Subschema pointer is not owned by this Schema instance");
+        }
+
+        return noConst;
+    }
+
+    /// Set of Subschema instances owned by this schema
+    std::set<Subschema*> subschemaSet;
+
+    /// Empty schema that can be reused by multiple constraints
+    const Subschema *sharedEmptySubschema;
+};
+
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/schema_parser.hpp b/examples/validator/valijson/include/valijson/schema_parser.hpp
new file mode 100644
index 0000000..c08dce2
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/schema_parser.hpp
@@ -0,0 +1,2120 @@
+#pragma once
+#ifndef __VALIJSON_SCHEMA_PARSER_HPP
+#define __VALIJSON_SCHEMA_PARSER_HPP
+
+#include <stdexcept>
+#include <iostream>
+#include <vector>
+#include <memory>
+#include <functional>
+
+#include <valijson/adapters/adapter.hpp>
+#include <valijson/constraints/concrete_constraints.hpp>
+#include <valijson/internal/debug.hpp>
+#include <valijson/internal/json_pointer.hpp>
+#include <valijson/internal/json_reference.hpp>
+#include <valijson/internal/uri.hpp>
+#include <valijson/constraint_builder.hpp>
+#include <valijson/schema.hpp>
+
+#ifdef __clang__
+#  pragma clang diagnostic push
+#  pragma clang diagnostic ignored "-Wunused-local-typedef"
+#endif
+
+namespace valijson {
+
+/**
+ * @brief  Parser for populating a Schema based on a JSON Schema document.
+ *
+ * The SchemaParser class supports Drafts 3 and 4 of JSON Schema, however
+ * Draft 3 support should be considered deprecated.
+ *
+ * The functions provided by this class have been templated so that they can
+ * be used with different Adapter types.
+ */
+class SchemaParser
+{
+public:
+    /// Supported versions of JSON Schema
+    enum Version {
+        kDraft3,      ///< @deprecated JSON Schema v3 has been superseded by v4
+        kDraft4
+    };
+
+    /// Version of JSON Schema that should be expected when parsing
+    const Version version;
+
+    /**
+     * @brief  Construct a new SchemaParser for a given version of JSON Schema
+     *
+     * @param  version  Version of JSON Schema that will be expected
+     */
+    SchemaParser(const Version version = kDraft4)
+      : version(version) { }
+
+    /**
+     * @brief  Release memory associated with custom ConstraintBuilders
+     */
+    ~SchemaParser()
+    {
+        for (ConstraintBuilders::iterator itr = constraintBuilders.begin();
+                itr != constraintBuilders.end(); ++itr) {
+            delete itr->second;
+        }
+    }
+
+    /**
+     * @brief  Struct to contain templated function type for fetching documents
+     */
+    template<typename AdapterType>
+    struct FunctionPtrs
+    {
+        typedef typename adapters::AdapterTraits<AdapterType>::DocumentType
+                DocumentType;
+
+        /// Templated function pointer type for fetching remote documents
+        typedef std::function< const DocumentType* (const std::string &uri) >  FetchDoc ;
+
+        /// Templated function pointer type for freeing fetched documents
+        typedef std::function< void (const DocumentType *)> FreeDoc ;
+    };
+
+    /**
+     * @brief  Add a custom contraint to this SchemaParser
+
+     * @param  key      name that will be used to identify relevant constraints
+     *                  while parsing a schema document
+     * @param  builder  pointer to a subclass of ConstraintBuilder that can
+     *                  parse custom constraints found in a schema document,
+     *                  and return an appropriate instance of Constraint; this
+     *                  class guarantees that it will take ownership of this
+     *                  pointer - unless this function throws an exception
+     *
+     * @todo   consider accepting a list of custom ConstraintBuilders in
+     *         constructor, so that this class remains immutable after
+     *         construction
+     *
+     * @todo   Add additional checks for key conflicts, empty keys, and
+     *         potential restrictions relating to case sensitivity
+     */
+    void addConstraintBuilder(const std::string &key,
+            const ConstraintBuilder *builder)
+    {
+        constraintBuilders.push_back(std::make_pair(key, builder));
+    }
+
+    /**
+     * @brief  Populate a Schema object from JSON Schema document
+     *
+     * When processing Draft 3 schemas, the parentSubschema and ownName pointers
+     * should be set in contexts where a 'required' constraint would be valid.
+     * These are used to add a RequiredConstraint object to the Schema that
+     * contains the required property.
+     *
+     * @param  node          Reference to node to parse
+     * @param  schema        Reference to Schema to populate
+     * @param  fetchDoc      Function to fetch remote JSON documents (optional)
+     */
+    template<typename AdapterType>
+    void populateSchema(
+        const AdapterType &node,
+        Schema &schema,
+        typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc = nullptr ,
+        typename FunctionPtrs<AdapterType>::FreeDoc freeDoc = nullptr )
+    {
+        if ((fetchDoc == nullptr ) ^ (freeDoc == nullptr)) {
+            throw std::runtime_error(
+                    "Remote document fetching cannot be enabled without both "
+                    "fetch and free functions");
+        }
+
+        typename DocumentCache<AdapterType>::Type docCache;
+        SchemaCache schemaCache;
+        try {
+            resolveThenPopulateSchema(schema, node, node, schema,
+                    opt::optional<std::string>(), "",
+                    fetchDoc, NULL, NULL, docCache, schemaCache);
+        } catch (...) {
+            freeDocumentCache<AdapterType>(docCache, freeDoc);
+            throw;
+        }
+
+        freeDocumentCache<AdapterType>(docCache, freeDoc);
+    }
+
+private:
+
+    typedef std::vector<std::pair<std::string, const ConstraintBuilder *> >
+        ConstraintBuilders;
+
+    ConstraintBuilders constraintBuilders;
+
+    template<typename AdapterType>
+    struct DocumentCache
+    {
+        typedef typename adapters::AdapterTraits<AdapterType>::DocumentType
+                DocumentType;
+
+        typedef std::map<std::string, const DocumentType*> Type;
+    };
+
+    typedef std::map<std::string, const Subschema *> SchemaCache;
+
+    /**
+     * @brief  Free memory used by fetched documents
+     *
+     * If a custom 'free' function has not been provided, then the default
+     * delete operator will be used.
+     *
+     * @param  docCache  collection of fetched documents to free
+     * @param  freeDoc   optional custom free function
+     */
+    template<typename AdapterType>
+    void freeDocumentCache(const typename DocumentCache<AdapterType>::Type
+            &docCache, typename FunctionPtrs<AdapterType>::FreeDoc freeDoc)
+    {
+        typedef typename DocumentCache<AdapterType>::Type DocCacheType;
+
+        for (const typename DocCacheType::value_type &v : docCache) {
+            freeDoc(v.second);
+        }
+    }
+
+    /**
+     * @brief  Find the absolute URI for a document, within a resolution scope
+     *
+     * This function captures five different cases that can occur when
+     * attempting to resolve a document URI within a particular resolution
+     * scope:
+     *
+     *  - resolution scope not present, but absolute document URI is
+     *       => document URI as-is
+     *  - resolution scope not present, and document URI is relative or absent
+     *       => no result
+     *  - resolution scope is present, and document URI is a relative path
+     *       => resolve document URI relative to resolution scope
+     *  - resolution scope is present, and document URI is absolute
+     *       => document URI as-is
+     *  - resolution scope is present, but document URI is not
+     *       => resolution scope as-is
+     *
+     * This function assumes that the resolution scope is absolute.
+     *
+     * When resolving a document URI relative to the resolution scope, the
+     * document URI should be used to replace the path, query and fragment
+     * portions of URI provided by the resolution scope.
+     */
+    virtual opt::optional<std::string> findAbsoluteDocumentUri(
+            const opt::optional<std::string> resolutionScope,
+            const opt::optional<std::string> documentUri)
+    {
+        if (resolutionScope) {
+            if (documentUri) {
+                if (internal::uri::isUriAbsolute(*documentUri)) {
+                    return *documentUri;
+                } else {
+                    return internal::uri::resolveRelativeUri(
+                            *resolutionScope, *documentUri);
+                }
+            } else {
+                return *resolutionScope;
+            }
+        } else if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
+            return *documentUri;
+        } else {
+            return opt::optional<std::string>();
+        }
+    }
+
+    /**
+     * @brief  Extract a JSON Reference string from a node
+     *
+     * @param  node    node to extract the JSON Reference from
+     * @param  result  reference to string to set with the result
+     *
+     * @throws std::invalid_argument if node is an object containing a `$ref`
+     *         property but with a value that cannot be interpreted as a string
+     *
+     * @return \c true if a JSON Reference was extracted; \c false otherwise
+     */
+    template<typename AdapterType>
+    bool extractJsonReference(const AdapterType &node, std::string &result)
+    {
+        if (!node.isObject()) {
+            return false;
+        }
+
+        const typename AdapterType::Object o = node.getObject();
+        const typename AdapterType::Object::const_iterator itr = o.find("$ref");
+        if (itr == o.end()) {
+            return false;
+        } else if (!itr->second.asString(result)) {
+            throw std::invalid_argument(
+                    "$ref property expected to contain string value.");
+        }
+
+        return true;
+    }
+
+    /**
+     * Sanitise an optional JSON Pointer, trimming trailing slashes
+     */
+    std::string sanitiseJsonPointer(const opt::optional<std::string> input)
+    {
+        if (input) {
+            // Trim trailing slash(es)
+            std::string sanitised = *input;
+            sanitised.erase(sanitised.find_last_not_of('/') + 1,
+                    std::string::npos);
+
+            return sanitised;
+        }
+
+        // If the JSON Pointer is not set, assume that the URI points to
+        // the root of the document
+        return "";
+    }
+
+    /**
+     * @brief  Search the schema cache for a schema matching a given key
+     *
+     * If the key is not present in the query cache, a NULL pointer will be
+     * returned, and the contents of the cache will remain unchanged. This is
+     * in contrast to the behaviour of the std::map [] operator, which would
+     * add the NULL pointer to the cache.
+     *
+     * @param  schemaCache  schema cache to query
+     * @param  queryKey     key to search for
+     *
+     * @return shared pointer to Schema if found, NULL pointer otherwise
+     */
+    static const Subschema * querySchemaCache(SchemaCache &schemaCache,
+            const std::string &queryKey)
+    {
+        const SchemaCache::iterator itr = schemaCache.find(queryKey);
+        if (itr == schemaCache.end()) {
+            return NULL;
+        }
+
+        return itr->second;
+    }
+
+    /**
+     * @brief  Add entries to the schema cache for a given list of keys
+     *
+     * @param  schemaCache   schema cache to update
+     * @param  keysToCreate  list of keys to create entries for
+     * @param  schema        shared pointer to schema that keys will map to
+     *
+     * @throws std::logic_error if any of the keys are already present in the
+     *         schema cache. This behaviour is intended to help detect incorrect
+     *         usage of the schema cache during development, and is not expected
+     *         to occur otherwise, even for malformed schemas.
+     */
+    void updateSchemaCache(SchemaCache &schemaCache,
+            const std::vector<std::string> &keysToCreate,
+            const Subschema *schema)
+    {
+        for (const std::string &keyToCreate : keysToCreate) {
+            const SchemaCache::value_type value(keyToCreate, schema);
+            if (!schemaCache.insert(value).second) {
+                throw std::logic_error(
+                        "Key '" + keyToCreate + "' already in schema cache.");
+            }
+        }
+    }
+
+    /**
+     * @brief  Recursive helper function for retrieving or creating schemas
+     *
+     * This function will be applied recursively until a concrete node is found.
+     * A concrete node is a node that contains actual schema constraints rather
+     * than a JSON Reference.
+     *
+     * This termination condition may be trigged by visiting the concrete node
+     * at the end of a series of $ref nodes, or by finding a schema for one of
+     * those $ref nodes in the schema cache. An entry will be added to the
+     * schema cache for each node visited on the path to the concrete node.
+     *
+     * @param  rootSchema    The Schema instance, and root subschema, through
+     *                       which other subschemas can be created and
+     *                       modified
+     * @param  rootNode      Reference to the node from which JSON References
+     *                       will be resolved when they refer to the current
+     *                       document
+     * @param  node          Reference to the node to parse
+     * @param  currentScope  URI for current resolution scope
+     * @param  nodePath      JSON Pointer representing path to current node
+     * @param  fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param  parentSchema  Optional pointer to the parent schema, used to
+     *                       support required keyword in Draft 3
+     * @param  ownName       Optional pointer to a node name, used to support
+     *                       the 'required' keyword in Draft 3
+     * @param  docCache      Cache of resolved and fetched remote documents
+     * @param  schemaCache   Cache of populated schemas
+     * @param  newCacheKeys  A list of keys that should be added to the cache
+     *                       when recursion terminates
+     */
+    template<typename AdapterType>
+    const Subschema * makeOrReuseSchema(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        const Subschema *parentSubschema,
+        const std::string *ownName,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache,
+        std::vector<std::string> &newCacheKeys)
+    {
+        std::string jsonRef;
+
+        // Check for the first termination condition (found a non-$ref node)
+        if (!extractJsonReference(node, jsonRef)) {
+
+            // Construct a key that we can use to search the schema cache for
+            // a schema corresponding to the current node
+            const std::string schemaCacheKey =
+                    currentScope ? (*currentScope + nodePath) : nodePath;
+
+            // Retrieve an existing schema from the cache if possible
+            const Subschema *cachedPtr =
+                    querySchemaCache(schemaCache, schemaCacheKey);
+
+            // Create a new schema otherwise
+            const Subschema *subschema = cachedPtr ? cachedPtr :
+                    rootSchema.createSubschema();
+
+            // Add cache entries for keys belonging to any $ref nodes that were
+            // visited before arriving at the current node
+            updateSchemaCache(schemaCache, newCacheKeys, subschema);
+
+            // Schema cache did not contain a pre-existing schema corresponding
+            // to the current node, so the schema that was returned will need
+            // to be populated
+            if (!cachedPtr) {
+                populateSchema(rootSchema, rootNode, node, *subschema,
+                        currentScope, nodePath, fetchDoc, parentSubschema,
+                        ownName, docCache, schemaCache);
+            }
+
+            return subschema;
+        }
+
+        // Returns a document URI if the reference points somewhere
+        // other than the current document
+        const opt::optional<std::string> documentUri =
+                internal::json_reference::getJsonReferenceUri(jsonRef);
+
+        // Extract JSON Pointer from JSON Reference, with any trailing
+        // slashes removed so that keys in the schema cache end
+        // consistently
+        const std::string actualJsonPointer = sanitiseJsonPointer(
+                internal::json_reference::getJsonReferencePointer(jsonRef));
+
+        // Determine the actual document URI based on the resolution
+        // scope. An absolute document URI will take precedence when
+        // present, otherwise we need to resolve the URI relative to
+        // the current resolution scope
+        const opt::optional<std::string> actualDocumentUri =
+                findAbsoluteDocumentUri(currentScope, documentUri);
+
+        // Construct a key to search the schema cache for an existing schema
+        const std::string queryKey = actualDocumentUri ?
+                (*actualDocumentUri + actualJsonPointer) : actualJsonPointer;
+
+        // Check for the second termination condition (found a $ref node that
+        // already has an entry in the schema cache)
+        const Subschema *cachedPtr = querySchemaCache(schemaCache, queryKey);
+        if (cachedPtr) {
+            updateSchemaCache(schemaCache, newCacheKeys, cachedPtr);
+            return cachedPtr;
+        }
+
+        if (actualDocumentUri && (!currentScope || *actualDocumentUri != *currentScope)) {
+            const typename FunctionPtrs<AdapterType>::DocumentType *newDoc = NULL;
+
+            // Have we seen this document before?
+            typename DocumentCache<AdapterType>::Type::iterator docCacheItr =
+                    docCache.find(*actualDocumentUri);
+            if (docCacheItr == docCache.end()) {
+                // Resolve reference against remote document
+                if (!fetchDoc) {
+                    throw std::runtime_error(
+                            "Fetching of remote JSON References not enabled.");
+                }
+
+                // Returns a pointer to the remote document that was
+                // retrieved, or null if retrieval failed. This class
+                // will take ownership of the pointer, and call freeDoc
+                // when it is no longer needed.
+                newDoc = fetchDoc(*actualDocumentUri);
+
+                // Can't proceed without the remote document
+                if (!newDoc) {
+                    throw std::runtime_error(
+                            "Failed to fetch referenced schema document: " +
+                            *actualDocumentUri);
+                }
+
+                typedef typename DocumentCache<AdapterType>::Type::value_type
+                        DocCacheValueType;
+
+                docCache.insert(DocCacheValueType(*actualDocumentUri, newDoc));
+
+            } else {
+                newDoc = docCacheItr->second;
+            }
+
+            const AdapterType newRootNode(*newDoc);
+
+            // Find where we need to be in the document
+            const AdapterType &referencedAdapter =
+                    internal::json_pointer::resolveJsonPointer(newRootNode,
+                            actualJsonPointer);
+
+            newCacheKeys.push_back(queryKey);
+
+            // Populate the schema, starting from the referenced node, with
+            // nested JSON References resolved relative to the new root node
+            return makeOrReuseSchema(rootSchema, newRootNode, referencedAdapter,
+                    currentScope, actualJsonPointer, fetchDoc, parentSubschema,
+                    ownName, docCache, schemaCache, newCacheKeys);
+
+        }
+
+        // JSON References in nested schema will be resolved relative to the
+        // current document
+        const AdapterType &referencedAdapter =
+                internal::json_pointer::resolveJsonPointer(
+                        rootNode, actualJsonPointer);
+
+        newCacheKeys.push_back(queryKey);
+
+        // Populate the schema, starting from the referenced node, with
+        // nested JSON References resolved relative to the new root node
+        return makeOrReuseSchema(rootSchema, rootNode, referencedAdapter,
+                currentScope, actualJsonPointer, fetchDoc, parentSubschema,
+                ownName, docCache, schemaCache, newCacheKeys);
+    }
+
+    /**
+     * @brief  Return pointer for the schema corresponding to a given node
+     *
+     * This function makes use of a schema cache, so that if the path to the
+     * current node is the same as one that has already been parsed and
+     * populated, a pointer to the existing Subschema will be returned.
+     *
+     * Should a series of $ref, or reference, nodes be resolved before reaching
+     * a concrete node, an entry will be added to the schema cache for each of
+     * the nodes in that path.
+     *
+     * @param  rootSchema    The Schema instance, and root subschema, through
+     *                       which other subschemas can be created and
+     *                       modified
+     * @param  rootNode      Reference to the node from which JSON References
+     *                       will be resolved when they refer to the current
+     *                       document
+     * @param  node          Reference to the node to parse
+     * @param  currentScope  URI for current resolution scope
+     * @param  nodePath      JSON Pointer representing path to current node
+     * @param  fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param  parentSchema  Optional pointer to the parent schema, used to
+     *                       support required keyword in Draft 3
+     * @param  ownName       Optional pointer to a node name, used to support
+     *                       the 'required' keyword in Draft 3
+     * @param  docCache      Cache of resolved and fetched remote documents
+     * @param  schemaCache   Cache of populated schemas
+     */
+    template<typename AdapterType>
+    const Subschema * makeOrReuseSchema(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        const Subschema *parentSubschema,
+        const std::string *ownName,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        std::vector<std::string> schemaCacheKeysToCreate;
+
+        return makeOrReuseSchema(rootSchema, rootNode, node, currentScope,
+                nodePath, fetchDoc, parentSubschema, ownName, docCache,
+                schemaCache, schemaCacheKeysToCreate);
+    }
+
+    /**
+     * @brief  Populate a Schema object from JSON Schema document
+     *
+     * When processing Draft 3 schemas, the parentSubschema and ownName pointers
+     * should be set in contexts where a 'required' constraint would be valid.
+     * These are used to add a RequiredConstraint object to the Schema that
+     * contains the required property.
+     *
+     * @param  rootSchema       The Schema instance, and root subschema, through
+     *                          which other subschemas can be created and
+     *                          modified
+     * @param  rootNode         Reference to the node from which JSON References
+     *                          will be resolved when they refer to the current
+     *                          document
+     * @param  node             Reference to node to parse
+     * @param  schema           Reference to Schema to populate
+     * @param  currentScope     URI for current resolution scope
+     * @param  nodePath         JSON Pointer representing path to current node
+     * @param  fetchDoc         Optional function to fetch remote JSON documents
+     * @param  parentSubschema  Optional pointer to the parent schema, used to
+     *                          support required keyword in Draft 3
+     * @param  ownName          Optional pointer to a node name, used to support
+     *                          the 'required' keyword in Draft 3
+     * @param  docCache         Cache of resolved and fetched remote documents
+     * @param  schemaCache      Cache of populated schemas
+     */
+    template<typename AdapterType>
+    void populateSchema(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const Subschema &subschema,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        const Subschema *parentSubschema,
+        const std::string *ownName,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        static_assert((std::is_convertible<AdapterType,
+            const valijson::adapters::Adapter &>::value),
+            "SchemaParser::populateSchema must be invoked with an "
+            "appropriate Adapter implementation");
+
+        if (!node.isObject()) {
+            std::string s;
+            s += "Expected node at ";
+            s += nodePath;
+            s += " to contain schema object; actual node type is: ";
+            s += internal::nodeTypeAsString(node);
+            throw std::runtime_error(s);
+        }
+
+        const typename AdapterType::Object object = node.asObject();
+        typename AdapterType::Object::const_iterator itr(object.end());
+
+        // Check for 'id' attribute and update current scope
+        opt::optional<std::string> updatedScope;
+        if ((itr = object.find("id")) != object.end() &&
+                itr->second.maybeString()) {
+            const std::string id = itr->second.asString();
+            rootSchema.setSubschemaId(&subschema, itr->second.asString());
+            if (!currentScope || internal::uri::isUriAbsolute(id)) {
+                updatedScope = id;
+            } else {
+                updatedScope = internal::uri::resolveRelativeUri(
+                        *currentScope, id);
+            }
+        } else {
+            updatedScope = currentScope;
+        }
+
+        if ((itr = object.find("allOf")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeAllOfConstraint(rootSchema, rootNode, itr->second,
+                            updatedScope, nodePath + "/allOf", fetchDoc,
+                            docCache, schemaCache),
+                    &subschema);
+        }
+
+        if ((itr = object.find("anyOf")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeAnyOfConstraint(rootSchema, rootNode, itr->second,
+                            updatedScope, nodePath + "/anyOf", fetchDoc,
+                            docCache, schemaCache),
+                    &subschema);
+        }
+
+        if ((itr = object.find("dependencies")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeDependenciesConstraint(rootSchema, rootNode,
+                            itr->second, updatedScope,
+                            nodePath + "/dependencies", fetchDoc, docCache,
+                            schemaCache),
+                    &subschema);
+        }
+
+        if ((itr = object.find("description")) != object.end()) {
+            if (itr->second.maybeString()) {
+                rootSchema.setSubschemaDescription(&subschema,
+                        itr->second.asString());
+            } else {
+                throw std::runtime_error(
+                        "'description' attribute should have a string value");
+            }
+        }
+
+        if ((itr = object.find("divisibleBy")) != object.end()) {
+            if (version == kDraft3) {
+                if (itr->second.maybeInteger()) {
+                    rootSchema.addConstraintToSubschema(
+                            makeMultipleOfIntConstraint(itr->second),
+                            &subschema);
+                } else if (itr->second.maybeDouble()) {
+                    rootSchema.addConstraintToSubschema(
+                            makeMultipleOfDoubleConstraint(itr->second),
+                            &subschema);
+                } else {
+                    throw std::runtime_error("Expected an numeric value for "
+                            " 'divisibleBy' constraint.");
+                }
+            } else {
+                throw std::runtime_error(
+                        "'divisibleBy' constraint not valid after draft 3");
+            }
+        }
+
+        if ((itr = object.find("enum")) != object.end()) {
+            rootSchema.addConstraintToSubschema(makeEnumConstraint(itr->second),
+                    &subschema);
+        }
+
+        {
+            const typename AdapterType::Object::const_iterator itemsItr =
+                    object.find("items");
+
+            if (object.end() != itemsItr) {
+                if (!itemsItr->second.isArray()) {
+                    rootSchema.addConstraintToSubschema(
+                            makeSingularItemsConstraint(rootSchema, rootNode,
+                                    itemsItr->second, updatedScope,
+                                    nodePath + "/items", fetchDoc, docCache,
+                                    schemaCache),
+                            &subschema);
+
+                } else {
+                    const typename AdapterType::Object::const_iterator
+                            additionalItemsItr = object.find("additionalItems");
+                    rootSchema.addConstraintToSubschema(
+                            makeLinearItemsConstraint(rootSchema, rootNode,
+                                    itemsItr != object.end() ?
+                                            &itemsItr->second : NULL,
+                                    additionalItemsItr != object.end() ?
+                                            &additionalItemsItr->second : NULL,
+                                    updatedScope, nodePath + "/items",
+                                    nodePath + "/additionalItems", fetchDoc,
+                                    docCache, schemaCache),
+                            &subschema);
+                }
+            }
+        }
+
+        if ((itr = object.find("maximum")) != object.end()) {
+            typename AdapterType::Object::const_iterator exclusiveMaximumItr =
+                    object.find("exclusiveMaximum");
+            if (exclusiveMaximumItr == object.end()) {
+                rootSchema.addConstraintToSubschema(
+                        makeMaximumConstraint<AdapterType>(itr->second, NULL),
+                        &subschema);
+            } else {
+                rootSchema.addConstraintToSubschema(
+                        makeMaximumConstraint(itr->second,
+                                &exclusiveMaximumItr->second),
+                        &subschema);
+            }
+        } else if (object.find("exclusiveMaximum") != object.end()) {
+            throw std::runtime_error(
+                    "'exclusiveMaximum' constraint only valid if a 'maximum' "
+                    "constraint is also present");
+        }
+
+        if ((itr = object.find("maxItems")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeMaxItemsConstraint(itr->second), &subschema);
+        }
+
+        if ((itr = object.find("maxLength")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeMaxLengthConstraint(itr->second), &subschema);
+        }
+
+        if ((itr = object.find("maxProperties")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeMaxPropertiesConstraint(itr->second), &subschema);
+        }
+
+        if ((itr = object.find("minimum")) != object.end()) {
+            typename AdapterType::Object::const_iterator exclusiveMinimumItr =
+                    object.find("exclusiveMinimum");
+            if (exclusiveMinimumItr == object.end()) {
+                rootSchema.addConstraintToSubschema(
+                        makeMinimumConstraint<AdapterType>(itr->second, NULL),
+                        &subschema);
+            } else {
+                rootSchema.addConstraintToSubschema(
+                        makeMinimumConstraint(itr->second,
+                                &exclusiveMinimumItr->second),
+                        &subschema);
+            }
+        } else if (object.find("exclusiveMinimum") != object.end()) {
+            throw std::runtime_error(
+                    "'exclusiveMinimum' constraint only valid if a 'minimum' "
+                    "constraint is also present");
+        }
+
+        if ((itr = object.find("minItems")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeMinItemsConstraint(itr->second), &subschema);
+        }
+
+        if ((itr = object.find("minLength")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeMinLengthConstraint(itr->second), &subschema);
+        }
+
+        if ((itr = object.find("minProperties")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeMinPropertiesConstraint(itr->second), &subschema);
+        }
+
+        if ((itr = object.find("multipleOf")) != object.end()) {
+            if (version == kDraft3) {
+                throw std::runtime_error(
+                        "'multipleOf' constraint not available in draft 3");
+            } else if (itr->second.maybeInteger()) {
+                rootSchema.addConstraintToSubschema(
+                        makeMultipleOfIntConstraint(itr->second),
+                        &subschema);
+            } else if (itr->second.maybeDouble()) {
+                rootSchema.addConstraintToSubschema(
+                        makeMultipleOfDoubleConstraint(itr->second),
+                        &subschema);
+            } else {
+                throw std::runtime_error("Expected an numeric value for "
+                        " 'divisibleBy' constraint.");
+            }
+        }
+
+        if ((itr = object.find("not")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeNotConstraint(rootSchema, rootNode, itr->second,
+                            updatedScope, nodePath + "/not", fetchDoc, docCache,
+                            schemaCache),
+                    &subschema);
+        }
+
+        if ((itr = object.find("oneOf")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeOneOfConstraint(rootSchema, rootNode, itr->second,
+                            updatedScope, nodePath + "/oneOf", fetchDoc,
+                            docCache, schemaCache),
+                    &subschema);
+        }
+
+        if ((itr = object.find("pattern")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makePatternConstraint(itr->second), &subschema);
+        }
+
+        {
+            // Check for schema keywords that require the creation of a
+            // PropertiesConstraint instance.
+            const typename AdapterType::Object::const_iterator
+                propertiesItr = object.find("properties"),
+                patternPropertiesItr = object.find("patternProperties"),
+                additionalPropertiesItr = object.find("additionalProperties");
+            if (object.end() != propertiesItr ||
+                object.end() != patternPropertiesItr ||
+                object.end() != additionalPropertiesItr) {
+                rootSchema.addConstraintToSubschema(
+                        makePropertiesConstraint(rootSchema, rootNode,
+                                propertiesItr != object.end() ?
+                                        &propertiesItr->second : NULL,
+                                patternPropertiesItr != object.end() ?
+                                        &patternPropertiesItr->second : NULL,
+                                additionalPropertiesItr != object.end() ?
+                                        &additionalPropertiesItr->second : NULL,
+                                updatedScope, nodePath + "/properties",
+                                nodePath + "/patternProperties",
+                                nodePath + "/additionalProperties",
+                                fetchDoc, &subschema, docCache, schemaCache),
+                        &subschema);
+            }
+        }
+
+        if ((itr = object.find("required")) != object.end()) {
+            if (version == kDraft3) {
+                if (parentSubschema && ownName) {
+                    opt::optional<constraints::RequiredConstraint>
+                            constraint = makeRequiredConstraintForSelf(
+                                    itr->second, *ownName);
+                    if (constraint) {
+                        rootSchema.addConstraintToSubschema(*constraint,
+                                parentSubschema);
+                    }
+                } else {
+                    throw std::runtime_error(
+                            "'required' constraint not valid here");
+                }
+            } else {
+                rootSchema.addConstraintToSubschema(
+                        makeRequiredConstraint(itr->second), &subschema);
+            }
+        }
+
+        if ((itr = object.find("title")) != object.end()) {
+            if (itr->second.maybeString()) {
+                rootSchema.setSubschemaTitle(&subschema,
+                        itr->second.asString());
+            } else {
+                throw std::runtime_error(
+                        "'title' attribute should have a string value");
+            }
+        }
+
+        if ((itr = object.find("type")) != object.end()) {
+            rootSchema.addConstraintToSubschema(
+                    makeTypeConstraint(rootSchema, rootNode, itr->second,
+                            updatedScope, nodePath + "/type", fetchDoc,
+                            docCache, schemaCache),
+                    &subschema);
+        }
+
+        if ((itr = object.find("uniqueItems")) != object.end()) {
+            opt::optional<constraints::UniqueItemsConstraint> constraint =
+                    makeUniqueItemsConstraint(itr->second);
+            if (constraint) {
+                rootSchema.addConstraintToSubschema(*constraint, &subschema);
+            }
+        }
+
+        for (ConstraintBuilders::const_iterator
+                builderItr  = constraintBuilders.begin();
+                builderItr != constraintBuilders.end(); ++builderItr) {
+            if ((itr = object.find(builderItr->first)) != object.end()) {
+                constraints::Constraint *constraint = NULL;
+                try {
+                    constraint = builderItr->second->make(itr->second);
+                    rootSchema.addConstraintToSubschema(*constraint,
+                            &subschema);
+                    delete constraint;
+                } catch (...) {
+                    delete constraint;
+                    throw;
+                }
+            }
+        }
+    }
+
+    /**
+     * @brief  Resolves a chain of JSON References before populating a schema
+     *
+     * This helper function is used directly by the publicly visible
+     * populateSchema function. It ensures that the node being parsed is a
+     * concrete node, and not a JSON Reference. This function will call itself
+     * recursively to resolve references until a concrete node is found.
+     *
+     * @param  rootSchema    The Schema instance, and root subschema, through
+     *                       which other subschemas can be created and modified
+     * @param  rootNode      Reference to the node from which JSON References
+     *                       will be resolved when they refer to the current
+     *                       document
+     * @param  node          Reference to node to parse
+     * @param  subschema     Reference to Schema to populate
+     * @param  currentScope  URI for current resolution scope
+     * @param  nodePath      JSON Pointer representing path to current node
+     * @param  fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param  parentSchema  Optional pointer to the parent schema, used to
+     *                       support required keyword in Draft 3
+     * @param  ownName       Optional pointer to a node name, used to support
+     *                       the 'required' keyword in Draft 3
+     * @param  docCache      Cache of resolved and fetched remote documents
+     * @param  schemaCache   Cache of populated schemas
+     */
+    template<typename AdapterType>
+    void resolveThenPopulateSchema(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const Subschema &subschema,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        const Subschema *parentSchema,
+        const std::string *ownName,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        std::string jsonRef;
+        if (!extractJsonReference(node, jsonRef)) {
+            populateSchema(rootSchema, rootNode, node, subschema, currentScope,
+                    nodePath, fetchDoc, parentSchema, ownName, docCache,
+                    schemaCache);
+            return;
+        }
+
+        // Returns a document URI if the reference points somewhere
+        // other than the current document
+        const opt::optional<std::string> documentUri =
+                internal::json_reference::getJsonReferenceUri(jsonRef);
+
+        // Extract JSON Pointer from JSON Reference
+        const std::string actualJsonPointer = sanitiseJsonPointer(
+                internal::json_reference::getJsonReferencePointer(jsonRef));
+
+        if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
+            // Resolve reference against remote document
+            if (!fetchDoc) {
+                throw std::runtime_error(
+                        "Fetching of remote JSON References not enabled.");
+            }
+
+            const typename DocumentCache<AdapterType>::DocumentType *newDoc =
+                    fetchDoc(*documentUri);
+
+            // Can't proceed without the remote document
+            if (!newDoc) {
+                throw std::runtime_error(
+                        "Failed to fetch referenced schema document: " +
+                        *documentUri);
+            }
+
+            // Add to document cache
+            typedef typename DocumentCache<AdapterType>::Type::value_type
+                    DocCacheValueType;
+
+            docCache.insert(DocCacheValueType(*documentUri, newDoc));
+
+            const AdapterType newRootNode(*newDoc);
+
+            const AdapterType &referencedAdapter =
+                internal::json_pointer::resolveJsonPointer(
+                        newRootNode, actualJsonPointer);
+
+            // TODO: Need to detect degenerate circular references
+            resolveThenPopulateSchema(rootSchema, newRootNode,
+                    referencedAdapter, subschema, opt::optional<std::string>(),
+                    actualJsonPointer, fetchDoc, parentSchema, ownName,
+                    docCache, schemaCache);
+
+        } else {
+            const AdapterType &referencedAdapter =
+                internal::json_pointer::resolveJsonPointer(
+                        rootNode, actualJsonPointer);
+
+            // TODO: Need to detect degenerate circular references
+            resolveThenPopulateSchema(rootSchema, rootNode, referencedAdapter,
+                    subschema, opt::optional<std::string>(),
+                    actualJsonPointer, fetchDoc,
+                    parentSchema, ownName, docCache, schemaCache);
+        }
+    }
+
+    /**
+     * @brief   Make a new AllOfConstraint object
+     *
+     * @param   rootSchema    The Schema instance, and root subschema, through
+     *                        which other subschemas can be created and modified
+     * @param   rootNode      Reference to the node from which JSON References
+     *                        will be resolved when they refer to the current
+     *                        document; used for recursive parsing of schemas
+     * @param   node          JSON node containing an array of child schemas
+     * @param   currentScope  URI for current resolution scope
+     * @param   nodePath      JSON Pointer representing path to current node
+     * @param   fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param   docCache      Cache of resolved and fetched remote documents
+     * @param   schemaCache   Cache of populated schemas
+     *
+     * @return  pointer to a new AllOfConstraint object that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::AllOfConstraint makeAllOfConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        if (!node.maybeArray()) {
+            throw std::runtime_error(
+                    "Expected array value for 'allOf' constraint.");
+        }
+
+        constraints::AllOfConstraint constraint;
+
+        int index = 0;
+        for ( const AdapterType schemaNode : node.asArray() ) {
+            if (schemaNode.maybeObject()) {
+                const std::string childPath = nodePath + "/" +
+                        std::to_string(index);
+                const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                        rootSchema, rootNode, schemaNode, currentScope,
+                        childPath, fetchDoc, NULL, NULL, docCache, schemaCache);
+                constraint.addSubschema(subschema);
+                index++;
+            } else {
+                throw std::runtime_error(
+                        "Expected array element to be an object value in "
+                        "'allOf' constraint.");
+            }
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new AnyOfConstraint object
+     *
+     * @param   rootSchema    The Schema instance, and root subschema, through
+     *                        which other subschemas can be created and modified
+     * @param   rootNode      Reference to the node from which JSON References
+     *                        will be resolved when they refer to the current
+     *                        document; used for recursive parsing of schemas
+     * @param   node          JSON node containing an array of child schemas
+     * @param   currentScope  URI for current resolution scope
+     * @param   nodePath      JSON Pointer representing path to current node
+     * @param   fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param   docCache      Cache of resolved and fetched remote documents
+     * @param   schemaCache   Cache of populated schemas
+     *
+     * @return  pointer to a new AnyOfConstraint object that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::AnyOfConstraint makeAnyOfConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        if (!node.maybeArray()) {
+            throw std::runtime_error(
+                    "Expected array value for 'anyOf' constraint.");
+        }
+
+        constraints::AnyOfConstraint constraint;
+
+        int index = 0;
+        for ( const AdapterType schemaNode : node.asArray() ) {
+            if (schemaNode.maybeObject()) {
+                const std::string childPath = nodePath + "/" +
+                        std::to_string(index);
+                const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                        rootSchema, rootNode, schemaNode, currentScope,
+                        childPath, fetchDoc, NULL, NULL, docCache, schemaCache);
+                constraint.addSubschema(subschema);
+                index++;
+            } else {
+                throw std::runtime_error(
+                        "Expected array element to be an object value in "
+                        "'anyOf' constraint.");
+            }
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new DependenciesConstraint object
+     *
+     * The dependencies for a property can be defined several ways. When parsing
+     * a Draft 4 schema, the following can be used:
+     *  - an array that lists the name of each property that must be present
+     *    if the dependent property is present
+     *  - an object that specifies a schema which must be satisfied if the
+     *    dependent property is present
+     *
+     * When parsing a Draft 3 schema, in addition to the formats above, the
+     * following format can be used:
+     *  - a string that names a single property that must be present if the
+     *    dependent property is presnet
+     *
+     * Multiple methods can be used in the same dependency constraint.
+     *
+     * If the format of any part of the the dependency node does not match one
+     * of these formats, an exception will be thrown.
+     *
+     * @param   rootSchema    The Schema instance, and root subschema, through
+     *                        which other subschemas can be created and modified
+     * @param   rootNode      Reference to the node from which JSON References
+     *                        will be resolved when they refer to the current
+     *                        document; used for recursive parsing of schemas
+     * @param   node          JSON node containing an object that defines a
+     *                        mapping of properties to their dependencies.
+     * @param   currentScope  URI for current resolution scope
+     * @param   nodePath      JSON Pointer representing path to current node
+     * @param   fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param   docCache      Cache of resolved and fetched remote documents
+     * @param   schemaCache   Cache of populated schemas
+     *
+     * @return  pointer to a new DependencyConstraint that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::DependenciesConstraint makeDependenciesConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        if (!node.maybeObject()) {
+            throw std::runtime_error("Expected object value for 'dependencies' constraint.");
+        }
+
+        constraints::DependenciesConstraint dependenciesConstraint;
+
+        // Process each of the dependency mappings defined by the object
+        for ( const typename AdapterType::ObjectMember member : node.asObject() ) {
+
+            // First, we attempt to parse the value of the dependency mapping
+            // as an array of strings. If the Adapter type does not support
+            // strict types, then an empty string or empty object will be cast
+            // to an array, and the resulting dependency list will be empty.
+            // This is equivalent to using an empty object, but does mean that
+            // if the user provides an actual string then this error will not
+            // be detected.
+            if (member.second.maybeArray()) {
+                // Parse an array of dependency names
+                std::vector<std::string> dependentPropertyNames;
+                for (const AdapterType dependencyName : member.second.asArray()) {
+                    if (dependencyName.maybeString()) {
+                        dependentPropertyNames.push_back(dependencyName.getString());
+                    } else {
+                        throw std::runtime_error("Expected string value in dependency list of property '" +
+                            member.first + "' in 'dependencies' constraint.");
+                    }
+                }
+
+                dependenciesConstraint.addPropertyDependencies(member.first,
+                        dependentPropertyNames);
+
+            // If the value of dependency mapping could not be processed as an
+            // array, we'll try to process it as an object instead. Note that
+            // strict type comparison is used here, since we've already
+            // exercised the flexibility by loosely-typed Adapter types. If the
+            // value of the dependency mapping is an object, then we'll try to
+            // process it as a dependent schema.
+            } else if (member.second.isObject()) {
+                // Parse dependent subschema
+                const Subschema *childSubschema =
+                        makeOrReuseSchema<AdapterType>(rootSchema, rootNode,
+                                member.second, currentScope, nodePath, fetchDoc,
+                                NULL, NULL, docCache, schemaCache);
+                dependenciesConstraint.addSchemaDependency(member.first,
+                        childSubschema);
+
+            // If we're supposed to be parsing a Draft3 schema, then the value
+            // of the dependency mapping can also be a string containing the
+            // name of a single dependency.
+            } else if (version == kDraft3 && member.second.isString()) {
+                dependenciesConstraint.addPropertyDependency(member.first,
+                        member.second.getString());
+
+            // All other types result in an exception being thrown.
+            } else {
+                throw std::runtime_error("Invalid dependencies definition.");
+            }
+        }
+
+        return dependenciesConstraint;
+    }
+
+    /**
+     * @brief   Make a new EnumConstraint object.
+     *
+     * @param   node  JSON node containing an array of values permitted by the
+     *                constraint.
+     *
+     * @return  pointer to a new EnumConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::EnumConstraint makeEnumConstraint(
+        const AdapterType &node)
+    {
+        // Make a copy of each value in the enum array
+        constraints::EnumConstraint constraint;
+        for (const AdapterType value : node.getArray()) {
+            constraint.addValue(value);
+        }
+
+        /// @todo This will make another copy of the values while constructing
+        /// the EnumConstraint. Move semantics in C++11 should make it possible
+        /// to avoid these copies without complicating the implementation of the
+        /// EnumConstraint class.
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new ItemsConstraint object.
+     *
+     * @param   rootSchema           The Schema instance, and root subschema,
+     *                               through which other subschemas can be
+     *                               created and modified
+     * @param   rootNode             Reference to the node from which JSON
+     *                               References will be resolved when they refer
+     *                               to the current document; used for recursive
+     *                               parsing of schemas
+     * @param   items                Optional pointer to a JSON node containing
+     *                               an object mapping property names to
+     *                               schemas.
+     * @param   additionalItems      Optional pointer to a JSON node containing
+     *                               an additional properties schema or a
+     *                               boolean value.
+     * @param   currentScope         URI for current resolution scope
+     * @param   itemsPath            JSON Pointer representing the path to
+     *                               the 'items' node
+     * @param   additionalItemsPath  JSON Pointer representing the path to
+     *                               the 'additionalItems' node
+     * @param   fetchDoc             Function to fetch remote JSON documents
+     *                               (optional)
+     * @param   docCache             Cache of resolved and fetched remote
+     *                               documents
+     * @param   schemaCache          Cache of populated schemas
+     *
+     * @return  pointer to a new ItemsConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::LinearItemsConstraint makeLinearItemsConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType *items,
+        const AdapterType *additionalItems,
+        const opt::optional<std::string> currentScope,
+        const std::string &itemsPath,
+        const std::string &additionalItemsPath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        constraints::LinearItemsConstraint constraint;
+
+        // Construct a Schema object for the the additionalItems constraint,
+        // if the additionalItems property is present
+        if (additionalItems) {
+            if (additionalItems->maybeBool()) {
+                // If the value of the additionalItems property is a boolean
+                // and is set to true, then additional array items do not need
+                // to satisfy any constraints.
+                if (additionalItems->asBool()) {
+                    constraint.setAdditionalItemsSubschema(
+                            rootSchema.emptySubschema());
+                }
+            } else if (additionalItems->maybeObject()) {
+                // If the value of the additionalItems property is an object,
+                // then it should be parsed into a Schema object, which will be
+                // used to validate additional array items.
+                const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                        rootSchema, rootNode, *additionalItems, currentScope,
+                        additionalItemsPath, fetchDoc, NULL, NULL, docCache,
+                        schemaCache);
+                constraint.setAdditionalItemsSubschema(subschema);
+            } else {
+                // Any other format for the additionalItems property will result
+                // in an exception being thrown.
+                throw std::runtime_error(
+                        "Expected bool or object value for 'additionalItems'");
+            }
+        } else {
+            // The default value for the additionalItems property is an empty
+            // object, which means that additional array items do not need to
+            // satisfy any constraints.
+            constraint.setAdditionalItemsSubschema(rootSchema.emptySubschema());
+        }
+
+        // Construct a Schema object for each item in the items array.
+        // If the items constraint is not provided, then array items
+        // will be validated against the additionalItems schema.
+        if (items) {
+            if (items->isArray()) {
+                // If the items constraint contains an array, then it should
+                // contain a list of child schemas which will be used to
+                // validate the values at the corresponding indexes in a target
+                // array.
+                int index = 0;
+                for (const AdapterType v : items->getArray()) {
+                    const std::string childPath = itemsPath + "/" +
+                            std::to_string(index);
+                    const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                            rootSchema, rootNode, v, currentScope, childPath,
+                            fetchDoc, NULL, NULL, docCache, schemaCache);
+                    constraint.addItemSubschema(subschema);
+                    index++;
+                }
+            } else {
+                throw std::runtime_error(
+                        "Expected array value for non-singular 'items' "
+                        "constraint.");
+            }
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new ItemsConstraint object.
+     *
+     * @param   rootSchema           The Schema instance, and root subschema,
+     *                               through which other subschemas can be
+     *                               created and modified
+     * @param   rootNode             Reference to the node from which JSON
+     *                               References will be resolved when they refer
+     *                               to the current document; used for recursive
+     *                               parsing of schemas
+     * @param   items                Optional pointer to a JSON node containing
+     *                               an object mapping property names to
+     *                               schemas.
+     * @param   additionalItems      Optional pointer to a JSON node containing
+     *                               an additional properties schema or a
+     *                               boolean value.
+     * @param   currentScope         URI for current resolution scope
+     * @param   itemsPath            JSON Pointer representing the path to
+     *                               the 'items' node
+     * @param   additionalItemsPath  JSON Pointer representing the path to
+     *                               the 'additionalItems' node
+     * @param   fetchDoc             Function to fetch remote JSON documents
+     *                               (optional)
+     * @param   docCache             Cache of resolved and fetched remote
+     *                               documents
+     * @param   schemaCache          Cache of populated schemas
+     *
+     * @return  pointer to a new ItemsConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::SingularItemsConstraint makeSingularItemsConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &items,
+        const opt::optional<std::string> currentScope,
+        const std::string &itemsPath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        constraints::SingularItemsConstraint constraint;
+
+        // Construct a Schema object for each item in the items array, if an
+        // array is provided, or a single Schema object, in an object value is
+        // provided. If the items constraint is not provided, then array items
+        // will be validated against the additionalItems schema.
+        if (items.isObject()) {
+            // If the items constraint contains an object value, then it
+            // should contain a Schema that will be used to validate all
+            // items in a target array. Any schema defined by the
+            // additionalItems constraint will be ignored.
+            const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                    rootSchema, rootNode, items, currentScope, itemsPath,
+                    fetchDoc, NULL, NULL, docCache, schemaCache);
+            constraint.setItemsSubschema(subschema);
+
+        } else if (items.maybeObject()) {
+            // If a loosely-typed Adapter type is being used, then we'll
+            // assume that an empty schema has been provided.
+            constraint.setItemsSubschema(rootSchema.emptySubschema());
+
+        } else {
+            // All other formats will result in an exception being thrown.
+            throw std::runtime_error(
+                    "Expected object value for singular 'items' "
+                    "constraint.");
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new MaximumConstraint object.
+     *
+     * @param   rootSchema        The Schema instance, and root subschema,
+     *                            through which other subschemas can be
+     *                            created and modified
+     * @param   rootNode          Reference to the node from which JSON
+     *                            References will be resolved when they refer
+     *                            to the current document; used for recursive
+     *                            parsing of schemas
+     * @param   node              JSON node containing the maximum value.
+     * @param   exclusiveMaximum  Optional pointer to a JSON boolean value that
+     *                            indicates whether maximum value is excluded
+     *                            from the range of permitted values.
+     *
+     * @return  pointer to a new MaximumConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::MaximumConstraint makeMaximumConstraint(
+        const AdapterType &node,
+        const AdapterType *exclusiveMaximum)
+    {
+        if (!node.maybeDouble()) {
+            throw std::runtime_error(
+                    "Expected numeric value for maximum constraint.");
+        }
+
+        constraints::MaximumConstraint constraint;
+        constraint.setMaximum(node.asDouble());
+
+        if (exclusiveMaximum) {
+            if (!exclusiveMaximum->maybeBool()) {
+                throw std::runtime_error(
+                        "Expected boolean value for exclusiveMaximum "
+                        "constraint.");
+            }
+
+            constraint.setExclusiveMaximum(exclusiveMaximum->asBool());
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new MaxItemsConstraint object.
+     *
+     * @param   node  JSON node containing an integer value representing the
+     *                maximum number of items that may be contaned by an array.
+     *
+     * @return  pointer to a new MaxItemsConstraint that belongs to the caller.
+     */
+    template<typename AdapterType>
+    constraints::MaxItemsConstraint makeMaxItemsConstraint(
+        const AdapterType &node)
+    {
+        if (node.maybeInteger()) {
+            const int64_t value = node.asInteger();
+            if (value >= 0) {
+                constraints::MaxItemsConstraint constraint;
+                constraint.setMaxItems(value);
+                return constraint;
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected non-negative integer value for 'maxItems' "
+                "constraint.");
+    }
+
+    /**
+     * @brief   Make a new MaxLengthConstraint object.
+     *
+     * @param   node  JSON node containing an integer value representing the
+     *                maximum length of a string.
+     *
+     * @return  pointer to a new MaxLengthConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::MaxLengthConstraint makeMaxLengthConstraint(
+        const AdapterType &node)
+    {
+        if (node.maybeInteger()) {
+            const int64_t value = node.asInteger();
+            if (value >= 0) {
+                constraints::MaxLengthConstraint constraint;
+                constraint.setMaxLength(value);
+                return constraint;
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected a non-negative integer value for 'maxLength' "
+                "constraint.");
+    }
+
+    /**
+     * @brief   Make a new MaxPropertiesConstraint object.
+     *
+     * @param   node  JSON node containing an integer value representing the
+     *                maximum number of properties that may be contained by an
+     *                object.
+     *
+     * @return  pointer to a new MaxPropertiesConstraint that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::MaxPropertiesConstraint makeMaxPropertiesConstraint(
+        const AdapterType &node)
+    {
+        if (node.maybeInteger()) {
+            int64_t value = node.asInteger();
+            if (value >= 0) {
+                constraints::MaxPropertiesConstraint constraint;
+                constraint.setMaxProperties(value);
+                return constraint;
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected a non-negative integer for 'maxProperties' "
+                "constraint.");
+    }
+
+    /**
+     * @brief  Make a new MinimumConstraint object.
+     *
+     * @param  node              JSON node containing an integer, representing
+     *                           the minimum value.
+     *
+     * @param  exclusiveMaximum  Optional pointer to a JSON boolean value that
+     *                           indicates whether the minimum value is
+     *                           excluded from the range of permitted values.
+     *
+     * @return  pointer to a new MinimumConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::MinimumConstraint makeMinimumConstraint(
+        const AdapterType &node,
+        const AdapterType *exclusiveMinimum)
+    {
+        if (!node.maybeDouble()) {
+            throw std::runtime_error(
+                    "Expected numeric value for minimum constraint.");
+        }
+
+        constraints::MinimumConstraint constraint;
+        constraint.setMinimum(node.asDouble());
+
+        if (exclusiveMinimum) {
+            if (!exclusiveMinimum->maybeBool()) {
+                throw std::runtime_error(
+                        "Expected boolean value for 'exclusiveMinimum' "
+                        "constraint.");
+            }
+
+            constraint.setExclusiveMinimum(exclusiveMinimum->asBool());
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief  Make a new MinItemsConstraint object.
+     *
+     * @param  node  JSON node containing an integer value representing the
+     *               minimum number of items that may be contained by an array.
+     *
+     * @return  pointer to a new MinItemsConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::MinItemsConstraint makeMinItemsConstraint(
+        const AdapterType &node)
+    {
+        if (node.maybeInteger()) {
+            const int64_t value = node.asInteger();
+            if (value >= 0) {
+                constraints::MinItemsConstraint constraint;
+                constraint.setMinItems(value);
+                return constraint;
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected a non-negative integer value for 'minItems' "
+                "constraint.");
+    }
+
+    /**
+     * @brief  Make a new MinLengthConstraint object.
+     *
+     * @param  node  JSON node containing an integer value representing the
+     *               minimum length of a string.
+     *
+     * @return  pointer to a new MinLengthConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::MinLengthConstraint makeMinLengthConstraint(
+        const AdapterType &node)
+    {
+        if (node.maybeInteger()) {
+            const int64_t value = node.asInteger();
+            if (value >= 0) {
+                constraints::MinLengthConstraint constraint;
+                constraint.setMinLength(value);
+                return constraint;
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected a non-negative integer value for 'minLength' "
+                "constraint.");
+    }
+
+
+    /**
+     * @brief   Make a new MaxPropertiesConstraint object.
+     *
+     * @param   node  JSON node containing an integer value representing the
+     *                minimum number of properties that may be contained by an
+     *                object.
+     *
+     * @return  pointer to a new MinPropertiesConstraint that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::MinPropertiesConstraint makeMinPropertiesConstraint(
+        const AdapterType &node)
+    {
+        if (node.maybeInteger()) {
+            int64_t value = node.asInteger();
+            if (value >= 0) {
+                constraints::MinPropertiesConstraint constraint;
+                constraint.setMinProperties(value);
+                return constraint;
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected a non-negative integer for 'minProperties' "
+                "constraint.");
+    }
+
+    /**
+     * @brief   Make a new MultipleOfDoubleConstraint object
+     *
+     * @param   node  JSON node containing an numeric value that a target value
+     *                must divide by in order to satisfy this constraint
+     *
+     * @return  a MultipleOfConstraint
+     */
+    template<typename AdapterType>
+    constraints::MultipleOfDoubleConstraint makeMultipleOfDoubleConstraint(
+        const AdapterType &node)
+    {
+        constraints::MultipleOfDoubleConstraint constraint;
+        constraint.setDivisor(node.asDouble());
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new MultipleOfIntConstraint object
+     *
+     * @param   node  JSON node containing a numeric value that a target value
+     *                must divide by in order to satisfy this constraint
+     *
+     * @return  a MultipleOfIntConstraint
+     */
+    template<typename AdapterType>
+    constraints::MultipleOfIntConstraint makeMultipleOfIntConstraint(
+            const AdapterType &node)
+    {
+        constraints::MultipleOfIntConstraint constraint;
+        constraint.setDivisor(node.asInteger());
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new NotConstraint object
+     *
+     * @param   rootSchema    The Schema instance, and root subschema, through
+     *                        which other subschemas can be created and modified
+     * @param   rootNode      Reference to the node from which JSON References
+     *                        will be resolved when they refer to the current
+     *                        document; used for recursive parsing of schemas
+     * @param   node          JSON node containing a schema
+     * @param   currentScope  URI for current resolution scope
+     * @param   nodePath      JSON Pointer representing path to current node
+     * @param   fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param   docCache      Cache of resolved and fetched remote documents
+     * @param   schemaCache   Cache of populated schemas
+     *
+     * @return  pointer to a new NotConstraint object that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::NotConstraint makeNotConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        if (node.maybeObject()) {
+            const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                    rootSchema, rootNode, node, currentScope, nodePath,
+                    fetchDoc, NULL, NULL, docCache, schemaCache);
+            constraints::NotConstraint constraint;
+            constraint.setSubschema(subschema);
+            return constraint;
+        }
+
+        throw std::runtime_error("Expected object value for 'not' constraint.");
+    }
+
+    /**
+     * @brief   Make a new OneOfConstraint object
+     *
+     * @param   rootSchema    The Schema instance, and root subschema, through
+     *                        which other subschemas can be created and modified
+     * @param   rootNode      Reference to the node from which JSON References
+     *                        will be resolved when they refer to the current
+     *                        document; used for recursive parsing of schemas
+     * @param   node          JSON node containing an array of child schemas
+     * @param   currentScope  URI for current resolution scope
+     * @param   nodePath      JSON Pointer representing path to current node
+     * @param   fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param   docCache      Cache of resolved and fetched remote documents
+     * @param   schemaCache   Cache of populated schemas
+     *
+     * @return  pointer to a new OneOfConstraint that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::OneOfConstraint makeOneOfConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        constraints::OneOfConstraint constraint;
+
+        int index = 0;
+        for ( const AdapterType schemaNode : node.getArray() ) {
+            const std::string childPath = nodePath + "/" +
+                    std::to_string(index);
+            const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                rootSchema, rootNode, schemaNode, currentScope, childPath,
+                fetchDoc, NULL, NULL, docCache, schemaCache);
+            constraint.addSubschema(subschema);
+            index++;
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new PatternConstraint object.
+     *
+     * @param   node      JSON node containing a pattern string
+     *
+     * @return  pointer to a new PatternConstraint object that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::PatternConstraint makePatternConstraint(
+        const AdapterType &node)
+    {
+        constraints::PatternConstraint constraint;
+        constraint.setPattern(node.getString());
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new Properties object.
+     *
+     * @param   rootSchema                The Schema instance, and root
+     *                                    subschema, through which other
+     *                                    subschemas can be created and modified
+     * @param   rootNode                  Reference to the node from which JSON
+     *                                    References will be resolved when they
+     *                                    refer to the current document; used
+     *                                    for recursive parsing of schemas
+     * @param   properties                Optional pointer to a JSON node
+     *                                    containing an object mapping property
+     *                                    names to schemas.
+     * @param   patternProperties         Optional pointer to a JSON node
+     *                                    containing an object mapping pattern
+     *                                    property names to schemas.
+     * @param   additionalProperties      Optional pointer to a JSON node
+     *                                    containing an additional properties
+     *                                    schema or a boolean value.
+     * @param   currentScope              URI for current resolution scope
+     * @param   propertiesPath            JSON Pointer representing the path to
+     *                                    the 'properties' node
+     * @param   patternPropertiesPath     JSON Pointer representing the path to
+     *                                    the 'patternProperties' node
+     * @param   additionalPropertiesPath  JSON Pointer representing the path to
+     *                                    the 'additionalProperties' node
+     * @param   fetchDoc                  Function to fetch remote JSON
+     *                                    documents (optional)
+     * @param   parentSubschema           Optional pointer to the Schema of the
+     *                                    parent object, needed to support the
+     *                                    'required' keyword in Draft 3
+     * @param   docCache                  Cache of resolved and fetched remote
+     *                                    documents
+     * @param   schemaCache               Cache of populated schemas
+     *
+     * @return  pointer to a new Properties that belongs to the caller
+     */
+    template<typename AdapterType>
+    constraints::PropertiesConstraint makePropertiesConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType *properties,
+        const AdapterType *patternProperties,
+        const AdapterType *additionalProperties,
+        const opt::optional<std::string> currentScope,
+        const std::string &propertiesPath,
+        const std::string &patternPropertiesPath,
+        const std::string &additionalPropertiesPath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        const Subschema *parentSubschema,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        typedef typename AdapterType::ObjectMember Member;
+
+        constraints::PropertiesConstraint constraint;
+
+        // Create subschemas for 'properties' constraint
+        if (properties) {
+            for (const Member m : properties->getObject()) {
+                const std::string &property = m.first;
+                const std::string childPath = propertiesPath + "/" + property;
+                const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                        rootSchema, rootNode, m.second, currentScope, childPath,
+                        fetchDoc, parentSubschema, &property, docCache,
+                        schemaCache);
+                constraint.addPropertySubschema(property, subschema);
+            }
+        }
+
+        // Create subschemas for 'patternProperties' constraint
+        if (patternProperties) {
+            for (const Member m : patternProperties->getObject()) {
+                const std::string &pattern = m.first;
+                const std::string childPath = patternPropertiesPath + "/" +
+                        pattern;
+                const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                        rootSchema, rootNode, m.second, currentScope, childPath,
+                        fetchDoc, parentSubschema, &pattern, docCache,
+                        schemaCache);
+                constraint.addPatternPropertySubschema(pattern, subschema);
+            }
+        }
+
+        // Create an additionalItems subschema if required
+        if (additionalProperties) {
+            // If additionalProperties has been set, check for a boolean value.
+            // Setting 'additionalProperties' to true allows the values of
+            // additional properties to take any form. Setting it false
+            // prohibits the use of additional properties.
+            // If additionalProperties is instead an object, it should be
+            // parsed as a schema. If additionalProperties has any other type,
+            // then the schema is not valid.
+            if (additionalProperties->isBool() ||
+                additionalProperties->maybeBool()) {
+                // If it has a boolean value that is 'true', then an empty
+                // schema should be used.
+                if (additionalProperties->asBool()) {
+                    constraint.setAdditionalPropertiesSubschema(
+                            rootSchema.emptySubschema());
+                }
+            } else if (additionalProperties->isObject()) {
+                // If additionalProperties is an object, it should be used as
+                // a child schema.
+                const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                        rootSchema, rootNode, *additionalProperties,
+                        currentScope, additionalPropertiesPath, fetchDoc, NULL,
+                        NULL, docCache, schemaCache);
+                constraint.setAdditionalPropertiesSubschema(subschema);
+            } else {
+                // All other types are invalid
+                throw std::runtime_error(
+                        "Invalid type for 'additionalProperties' constraint.");
+            }
+        } else {
+            // If an additionalProperties constraint is not provided, then the
+            // default value is an empty schema.
+            constraint.setAdditionalPropertiesSubschema(
+                    rootSchema.emptySubschema());
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new RequiredConstraint.
+     *
+     * This function is used to create new RequiredContraint objects for
+     * Draft 3 schemas.
+     *
+     * @param   node  Node containing a boolean value.
+     * @param   name  Name of the required attribute.
+     *
+     * @return  pointer to a new RequiredConstraint object that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    opt::optional<constraints::RequiredConstraint>
+            makeRequiredConstraintForSelf(const AdapterType &node,
+                    const std::string &name)
+    {
+        if (!node.maybeBool()) {
+            throw std::runtime_error("Expected boolean value for 'required' attribute.");
+        }
+
+        if (node.asBool()) {
+            constraints::RequiredConstraint constraint;
+            constraint.addRequiredProperty(name);
+            return constraint;
+        }
+
+        return opt::optional<constraints::RequiredConstraint>();
+    }
+
+    /**
+     * @brief   Make a new RequiredConstraint.
+     *
+     * This function is used to create new RequiredContraint objects for
+     * Draft 4 schemas.
+     *
+     * @param   node  Node containing an array of strings.
+     *
+     * @return  pointer to a new RequiredConstraint object that belongs to the
+     *          caller
+     */
+    template<typename AdapterType>
+    constraints::RequiredConstraint makeRequiredConstraint(
+        const AdapterType &node)
+    {
+        constraints::RequiredConstraint constraint;
+
+        for (const AdapterType v : node.getArray()) {
+            if (!v.isString()) {
+                throw std::runtime_error("Expected required property name to "
+                        "be a string value");
+            }
+
+            constraint.addRequiredProperty(v.getString());
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new TypeConstraint object
+     *
+     * @param   rootSchema    The Schema instance, and root subschema, through
+     *                        which other subschemas can be created and modified
+     * @param   rootNode      Reference to the node from which JSON References
+     *                        will be resolved when they refer to the current
+     *                        document; used for recursive parsing of schemas
+     * @param   node          Node containing the name of a JSON type
+     * @param   currentScope  URI for current resolution scope
+     * @param   nodePath      JSON Pointer representing path to current node
+     * @param   fetchDoc      Function to fetch remote JSON documents (optional)
+     * @param   docCache      Cache of resolved and fetched remote documents
+     * @param   schemaCache   Cache of populated schemas
+     *
+     * @return  pointer to a new TypeConstraint object.
+     */
+    template<typename AdapterType>
+    constraints::TypeConstraint makeTypeConstraint(
+        Schema &rootSchema,
+        const AdapterType &rootNode,
+        const AdapterType &node,
+        const opt::optional<std::string> currentScope,
+        const std::string &nodePath,
+        const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
+        typename DocumentCache<AdapterType>::Type &docCache,
+        SchemaCache &schemaCache)
+    {
+        typedef constraints::TypeConstraint TypeConstraint;
+
+        TypeConstraint constraint;
+
+        if (node.isString()) {
+            const TypeConstraint::JsonType type =
+                    TypeConstraint::jsonTypeFromString(node.getString());
+
+            if (type == TypeConstraint::kAny && version == kDraft4) {
+                throw std::runtime_error(
+                        "'any' type is not supported in version 4 schemas.");
+            }
+
+            constraint.addNamedType(type);
+
+        } else if (node.isArray()) {
+            int index = 0;
+            for (const AdapterType v : node.getArray()) {
+                if (v.isString()) {
+                    const TypeConstraint::JsonType type =
+                            TypeConstraint::jsonTypeFromString(v.getString());
+
+                    if (type == TypeConstraint::kAny && version == kDraft4) {
+                        throw std::runtime_error(
+                                "'any' type is not supported in version 4 "
+                                "schemas.");
+                    }
+
+                    constraint.addNamedType(type);
+
+                } else if (v.isObject() && version == kDraft3) {
+                    const std::string childPath = nodePath + "/" +
+                            std::to_string(index);
+                    const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                            rootSchema, rootNode, v, currentScope, childPath,
+                            fetchDoc, NULL, NULL, docCache, schemaCache);
+                    constraint.addSchemaType(subschema);
+
+                } else {
+                    throw std::runtime_error("Type name should be a string.");
+                }
+
+                index++;
+            }
+
+        } else if (node.isObject() && version == kDraft3) {
+            const Subschema *subschema = makeOrReuseSchema<AdapterType>(
+                    rootSchema, rootNode, node, currentScope, nodePath,
+                    fetchDoc, NULL, NULL, docCache, schemaCache);
+            constraint.addSchemaType(subschema);
+
+        } else {
+            throw std::runtime_error("Type name should be a string.");
+        }
+
+        return constraint;
+    }
+
+    /**
+     * @brief   Make a new UniqueItemsConstraint object.
+     *
+     * @param   node  Node containing a boolean value.
+     *
+     * @return  pointer to a new UniqueItemsConstraint object that belongs to
+     *          the caller, or NULL if the boolean value is false.
+     */
+    template<typename AdapterType>
+    opt::optional<constraints::UniqueItemsConstraint>
+            makeUniqueItemsConstraint(const AdapterType &node)
+    {
+        if (node.isBool() || node.maybeBool()) {
+            // If the boolean value is true, this function will return a pointer
+            // to a new UniqueItemsConstraint object. If it is value, then the
+            // constraint is redundant, so NULL is returned instead.
+            if (node.asBool()) {
+                return constraints::UniqueItemsConstraint();
+            } else {
+                return opt::optional<constraints::UniqueItemsConstraint>();
+            }
+        }
+
+        throw std::runtime_error(
+                "Expected boolean value for 'uniqueItems' constraint.");
+    }
+
+};
+
+}  // namespace valijson
+
+#ifdef __clang__
+#  pragma clang diagnostic pop
+#endif
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/subschema.hpp b/examples/validator/valijson/include/valijson/subschema.hpp
new file mode 100644
index 0000000..f6c4068
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/subschema.hpp
@@ -0,0 +1,286 @@
+#pragma once
+#ifndef __VALIJSON_SUBSCHEMA_HPP
+#define __VALIJSON_SUBSCHEMA_HPP
+
+#include <vector>
+
+#include <memory>
+
+#include <valijson/constraints/constraint.hpp>
+#include <valijson/internal/optional.hpp>
+
+namespace valijson {
+
+/**
+ * Represents a sub-schema within a JSON Schema
+ *
+ * While all JSON Schemas have at least one sub-schema, the root, some will
+ * have additional sub-schemas that are defined as part of constraints that are
+ * included in the schema. For example, a 'oneOf' constraint maintains a set of
+ * references to one or more nested sub-schemas. As per the definition of a 
+ * oneOf constraint, a document is valid within that constraint if it validates
+ * against one of the nested sub-schemas.
+ */
+class Subschema
+{
+public:
+    /// Typedef for custom new-/malloc-like function
+    typedef void * (*CustomAlloc)(size_t size);
+
+    /// Typedef for custom free-like function
+    typedef void (*CustomFree)(void *);
+
+    /// Typedef the Constraint class into the local namespace for convenience
+    typedef constraints::Constraint Constraint;
+
+    /// Typedef for a function that can be applied to each of the Constraint
+    /// instances owned by a Schema.
+    typedef std::function<bool (const Constraint &)> ApplyFunction;
+
+    /**
+     * @brief  Construct a new Subschema object
+     */
+    Subschema()
+      : allocFn(::operator new)
+      , freeFn(::operator delete) { }
+
+    /**
+     * @brief  Construct a new Subschema using custom memory management
+     *         functions
+     *
+     * @param  allocFn  malloc- or new-like function to allocate memory
+     *                  within Schema, such as for Subschema instances
+     * @param  freeFn   free-like function to free memory allocated with
+     *                  the `customAlloc` function
+     */
+    Subschema(CustomAlloc allocFn, CustomFree freeFn)
+      : allocFn(allocFn)
+      , freeFn(freeFn) { }
+
+    /**
+     * @brief  Clean up and free all memory managed by the Subschema
+     */
+    virtual ~Subschema()
+    {
+        try {
+            for (std::vector<const Constraint *>::iterator itr =
+                    constraints.begin(); itr != constraints.end(); ++itr) {
+                Constraint *constraint = const_cast<Constraint *>(*itr);
+                constraint->~Constraint();
+                freeFn(constraint);
+            }
+            constraints.clear();
+        } catch (const std::exception &e) {
+            fprintf(stderr, "Caught an exception in Subschema destructor: %s",
+                    e.what());
+        }
+    }
+
+    /**
+     * @brief  Add a constraint to this sub-schema
+     *
+     * The constraint will be copied before being added to the list of
+     * constraints for this Subschema. Note that constraints will be copied
+     * only as deep as references to other Subschemas - e.g. copies of
+     * constraints that refer to sub-schemas, will continue to refer to the
+     * same Subschema instances.
+     *
+     * @param  constraint  Reference to the constraint to copy
+     */
+    void addConstraint(const Constraint &constraint)
+    {
+        Constraint *newConstraint = constraint.clone(allocFn, freeFn);
+        try {
+            constraints.push_back(newConstraint);
+        } catch (...) {
+            newConstraint->~Constraint();
+            freeFn(newConstraint);
+            throw;
+        }
+    }
+
+    /**
+     * @brief  Invoke a function on each child Constraint
+     *
+     * This function will apply the callback function to each constraint in
+     * the Subschema, even if one of the invokations returns \c false. However,
+     * if one or more invokations of the callback function return \c false,
+     * this function will also return \c false.
+     *
+     * @returns  \c true if all invokations of the callback function are
+     *           successful, \c false otherwise
+     */
+    bool apply(ApplyFunction &applyFunction) const
+    {
+        bool allTrue = true;
+        for (const Constraint *constraint : constraints) {
+            allTrue = allTrue && applyFunction(*constraint);
+        }
+
+        return allTrue;
+    }
+
+    /**
+     * @brief  Invoke a function on each child Constraint
+     *
+     * This is a stricter version of the apply() function that will return
+     * immediately if any of the invokations of the callback function return
+     * \c false.
+     *
+     * @returns  \c true if all invokations of the callback function are
+     *           successful, \c false otherwise
+     */
+    bool applyStrict(ApplyFunction &applyFunction) const
+    {
+        for (const Constraint *constraint : constraints) {
+            if (!applyFunction(*constraint)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief  Get the description associated with this sub-schema
+     *
+     * @throws  std::runtime_error if a description has not been set
+     *
+     * @returns  string containing sub-schema description
+     */
+    std::string getDescription() const
+    {
+        if (description) {
+            return *description;
+        }
+
+        throw std::runtime_error("Schema does not have a description");
+    }
+
+    /**
+     * @brief  Get the ID associated with this sub-schema
+     *
+     * @throws  std::runtime_error if an ID has not been set
+     *
+     * @returns  string containing sub-schema ID
+     */
+    std::string getId() const
+    {
+        if (id) {
+            return *id;
+        }
+
+        throw std::runtime_error("Schema does not have an ID");
+    }
+
+    /**
+     * @brief  Get the title associated with this sub-schema
+     *
+     * @throws  std::runtime_error if a title has not been set
+     *
+     * @returns  string containing sub-schema title
+     */
+    std::string getTitle() const
+    {
+        if (title) {
+            return *title;
+        }
+
+        throw std::runtime_error("Schema does not have a title");
+    }
+
+    /**
+     * @brief  Check whether this sub-schema has a description
+     *
+     * @return boolean value
+     */
+    bool hasDescription() const
+    {
+        return static_cast<bool>(description);
+    }
+
+    /**
+     * @brief  Check whether this sub-schema has an ID
+     *
+     * @return  boolean value
+     */
+    bool hasId() const
+    {
+        return static_cast<bool>(id);
+    }
+
+    /**
+     * @brief  Check whether this sub-schema has a title
+     *
+     * @return  boolean value
+     */
+    bool hasTitle() const
+    {
+        return static_cast<bool>(title);
+    }
+
+    /**
+     * @brief  Set the description for this sub-schema
+     *
+     * The description will not be used for validation, but may be used as part
+     * of the user interface for interacting with schemas and sub-schemas. As
+     * an example, it may be used as part of the validation error descriptions
+     * that are produced by the Validator and ValidationVisitor classes.
+     *
+     * @param  description  new description
+     */
+    void setDescription(const std::string &description)
+    {
+        this->description = description;
+    }
+
+    void setId(const std::string &id)
+    {
+        this->id = id;
+    }
+
+    /**
+     * @brief  Set the title for this sub-schema
+     *
+     * The title will not be used for validation, but may be used as part
+     * of the user interface for interacting with schemas and sub-schema. As an
+     * example, it may be used as part of the validation error descriptions 
+     * that are produced by the Validator and ValidationVisitor classes.
+     *
+     * @param  title  new title
+     */
+    void setTitle(const std::string &title)
+    {
+        this->title = title;
+    }
+
+protected:
+
+    CustomAlloc allocFn;
+
+    CustomFree freeFn;
+
+private:
+
+    // Disable copy construction
+    Subschema(const Subschema &);
+
+    // Disable copy assignment
+    Subschema & operator=(const Subschema &);
+
+    /// List of pointers to constraints that apply to this schema.
+    std::vector<const Constraint *> constraints;
+
+    /// Schema description (optional)
+    opt::optional<std::string> description;
+
+    /// Id to apply when resolving the schema URI
+    opt::optional<std::string> id;
+
+    /// Title string associated with the schema (optional)
+    opt::optional<std::string> title;
+};
+
+} // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/file_utils.hpp b/examples/validator/valijson/include/valijson/utils/file_utils.hpp
new file mode 100644
index 0000000..2a9f724
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/file_utils.hpp
@@ -0,0 +1,48 @@
+#pragma once
+#ifndef __VALIJSON_FILE_UTILS_HPP
+#define __VALIJSON_FILE_UTILS_HPP
+
+#include <fstream>
+#include <limits>
+
+namespace valijson {
+namespace utils {
+
+/**
+ * Load a file into a string
+ *
+ * @param  path  path to the file to be loaded
+ * @param  dest  string into which file should be loaded
+ *
+ * @return  true if loaded, false otherwise
+ */
+inline bool loadFile(const std::string &path, std::string &dest)
+{
+    // Open file for reading
+    std::ifstream file(path.c_str());
+    if (!file.is_open()) {
+        return false;
+    }
+
+    // Allocate space for file contents
+    file.seekg(0, std::ios::end);
+    const std::streamoff offset = file.tellg();
+    if (offset < 0 || offset > std::numeric_limits<unsigned int>::max()) {
+        return false;
+    }
+
+    dest.clear();
+    dest.reserve(static_cast<unsigned int>(offset));
+
+    // Assign file contents to destination string
+    file.seekg(0, std::ios::beg);
+    dest.assign(std::istreambuf_iterator<char>(file),
+                std::istreambuf_iterator<char>());
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/json11_utils.hpp b/examples/validator/valijson/include/valijson/utils/json11_utils.hpp
new file mode 100644
index 0000000..32e4f98
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/json11_utils.hpp
@@ -0,0 +1,39 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_JSON11_UTILS_HPP
+#define __VALIJSON_UTILS_JSON11_UTILS_HPP
+
+#include <iostream>
+
+#include <json11.hpp>
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, json11::Json &document)
+{
+    // Load schema JSON from file
+    std::string file;
+    if (!loadFile(path, file)) {
+        std::cerr << "Failed to load json from file '" << path << "'." << std::endl;
+        return false;
+    }
+
+    // Parse schema
+    std::string err;
+    document = json11::Json::parse(file, err);
+    if (!err.empty()) {
+        std::cerr << "json11 failed to parse the document:" << std::endl
+                  << "Parse error: " << err << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
+
diff --git a/examples/validator/valijson/include/valijson/utils/jsoncpp_utils.hpp b/examples/validator/valijson/include/valijson/utils/jsoncpp_utils.hpp
new file mode 100644
index 0000000..ea60184
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/jsoncpp_utils.hpp
@@ -0,0 +1,37 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_JSONCPP_UTILS_HPP
+#define __VALIJSON_UTILS_JSONCPP_UTILS_HPP
+
+#include <iostream>
+
+#include <json/json.h>
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, Json::Value &document)
+{
+    // Load schema JSON from file
+    std::string file;
+    if (!loadFile(path, file)) {
+        std::cerr << "Failed to load json from file '" << path << "'." << std::endl;
+        return false;
+    }
+
+    Json::Reader reader;
+    bool parsingSuccessful = reader.parse(file, document);
+    if (!parsingSuccessful) {
+        std::cerr << "Jsoncpp parser failed to parse the document:" << std::endl
+                  << reader.getFormattedErrorMessages();
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/nlohmann_json_utils.hpp b/examples/validator/valijson/include/valijson/utils/nlohmann_json_utils.hpp
new file mode 100644
index 0000000..01838d8
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/nlohmann_json_utils.hpp
@@ -0,0 +1,37 @@
+#pragma once
+#ifndef VALIJSON_NLOHMANN_JSON_UTILS_HPP
+#define VALIJSON_NLOHMANN_JSON_UTILS_HPP
+
+#include <iostream>
+
+#include <json.hpp>
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, nlohmann::json &document) {
+    // Load schema JSON from file
+    std::string file;
+    if (!loadFile(path, file)) {
+        std::cerr << "Failed to load json from file '" << path << "'."
+                  << std::endl;
+        return false;
+    }
+
+    // Parse schema
+    try {
+        document = nlohmann::json::parse(file);
+    } catch (std::invalid_argument const& exception) {
+        std::cerr << "nlohmann::json failed to parse the document\n"
+            << "Parse error:" << exception.what() << "\n";
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif //VALIJSON_NLOHMANN_JSON_UTILS_HPP
diff --git a/examples/validator/valijson/include/valijson/utils/picojson_utils.hpp b/examples/validator/valijson/include/valijson/utils/picojson_utils.hpp
new file mode 100644
index 0000000..2ca4d46
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/picojson_utils.hpp
@@ -0,0 +1,37 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_PICOJSON_UTILS_HPP
+#define __VALIJSON_UTILS_PICOJSON_UTILS_HPP
+
+#include <iostream>
+
+#include <picojson.h>
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, picojson::value &document)
+{
+    // Load schema JSON from file
+    std::string file;
+    if (!loadFile(path, file)) {
+        std::cerr << "Failed to load json from file '" << path << "'." << std::endl;
+        return false;
+    }
+
+    // Parse schema
+    std::string err = picojson::parse(document, file);
+    if (!err.empty()) {
+        std::cerr << "PicoJson failed to parse the document:" << std::endl
+                  << "Parse error: " << err << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/poco_json_utils.hpp b/examples/validator/valijson/include/valijson/utils/poco_json_utils.hpp
new file mode 100644
index 0000000..747a7b4
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/poco_json_utils.hpp
@@ -0,0 +1,40 @@
+#pragma once
+#ifndef VALIJSON_POCO_JSON_UTILS_HPP
+#define VALIJSON_POCO_JSON_UTILS_HPP
+
+#include <iostream>
+
+#include <Poco/JSON/JSONException.h>
+#include <Poco/JSON/Object.h>
+#include <Poco/JSON/Parser.h>
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, Poco::Dynamic::Var &document) {
+    // Load schema JSON from file
+    std::string file;
+    if (!loadFile(path, file)) {
+        std::cerr << "Failed to load json from file '" << path << "'."
+                  << std::endl;
+        return false;
+    }
+
+    // Parse schema
+    try {
+        document = Poco::JSON::Parser().parse(file);
+    } catch (Poco::Exception const& exception) {
+        std::cerr << "Poco::JSON failed to parse the document\n"
+            << "Parse error:" << exception.what() << "\n";
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif //VALIJSON_POCO_JSON_UTILS_HPP
diff --git a/examples/validator/valijson/include/valijson/utils/property_tree_utils.hpp b/examples/validator/valijson/include/valijson/utils/property_tree_utils.hpp
new file mode 100644
index 0000000..8b987e0
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/property_tree_utils.hpp
@@ -0,0 +1,40 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_PROPERTY_TREE_UTILS_HPP
+#define __VALIJSON_UTILS_PROPERTY_TREE_UTILS_HPP
+
+#include <iostream>
+#include <sstream>
+
+#include <boost/property_tree/ptree.hpp>
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wshorten-64-to-32"
+# include <boost/property_tree/json_parser.hpp>
+# pragma clang diagnostic pop
+#else
+# include <boost/property_tree/json_parser.hpp>
+#endif
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, boost::property_tree::ptree &document)
+{
+    try {
+        boost::property_tree::read_json(path, document);
+    } catch (std::exception &e) {
+        std::cerr << "Boost Property Tree JSON parser failed to parse the document:" << std::endl;
+        std::cerr << e.what() << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/qtjson_utils.hpp b/examples/validator/valijson/include/valijson/utils/qtjson_utils.hpp
new file mode 100644
index 0000000..e130aa6
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/qtjson_utils.hpp
@@ -0,0 +1,48 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_QTJSON_UTILS_HPP
+#define __VALIJSON_UTILS_QTJSON_UTILS_HPP
+
+#include <QFile>
+
+#include <QJsonDocument>
+#include <QJsonObject>
+
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+inline bool loadDocument(const std::string &path, QJsonValue &root)
+{
+    // Load schema JSON from file
+    QFile file(QString::fromStdString(path));
+    if (!file.open(QFile::ReadOnly)) {
+        std::cerr << "Failed to load json from file '" << path << "'." << std::endl;
+        return false;
+    }
+
+    QByteArray data = file.readAll();
+
+    // Parse schema
+    QJsonParseError parseError;
+    QJsonDocument doc = QJsonDocument::fromJson(data);
+    if (doc.isNull()) {
+        std::cerr << "qt failed to parse the document:" << std::endl
+                  << parseError.errorString().toStdString() << std::endl;
+        return false;
+    } else if (doc.isObject()) {
+        root = QJsonValue(doc.object());
+    } else if (doc.isArray()) {
+        root = QJsonValue(doc.array());
+    } else if (doc.isEmpty()) {
+        root = QJsonValue();
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/rapidjson_utils.hpp b/examples/validator/valijson/include/valijson/utils/rapidjson_utils.hpp
new file mode 100644
index 0000000..cf7a895
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/rapidjson_utils.hpp
@@ -0,0 +1,39 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_RAPIDJSON_UTILS_HPP
+#define __VALIJSON_UTILS_RAPIDJSON_UTILS_HPP
+
+#include <iostream>
+
+#include <rapidjson/document.h>
+
+#include <valijson/utils/file_utils.hpp>
+
+namespace valijson {
+namespace utils {
+
+template<typename Encoding, typename Allocator>
+inline bool loadDocument(const std::string &path, rapidjson::GenericDocument<Encoding, Allocator> &document)
+{
+    // Load schema JSON from file
+    std::string file;
+    if (!loadFile(path, file)) {
+        std::cerr << "Failed to load json from file '" << path << "'." << std::endl;
+        return false;
+    }
+
+    // Parse schema
+    document.template Parse<0>(file.c_str());
+    if (document.HasParseError()) {
+        std::cerr << "RapidJson failed to parse the document:" << std::endl;
+        std::cerr << "Parse error: " << document.GetParseError() << std::endl;
+        std::cerr << "Near: " << file.substr((std::max)(size_t(0), document.GetErrorOffset() - 20), 40) << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/utils/utf8_utils.hpp b/examples/validator/valijson/include/valijson/utils/utf8_utils.hpp
new file mode 100644
index 0000000..4c3bc48
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/utils/utf8_utils.hpp
@@ -0,0 +1,64 @@
+#pragma once
+#ifndef __VALIJSON_UTILS_UTF8_UTILS_HPP
+#define __VALIJSON_UTILS_UTF8_UTILS_HPP
+
+#include <stdexcept>
+
+/*
+  Basic UTF-8 manipulation routines, adapted from code that was released into
+  the public domain by Jeff Bezanson.
+*/
+
+namespace valijson {
+namespace utils {
+
+static const uint32_t offsetsFromUTF8[6] = {
+    0x00000000UL, 0x00003080UL, 0x000E2080UL,
+    0x03C82080UL, 0xFA082080UL, 0x82082080UL
+};
+
+/* is c the start of a utf8 sequence? */
+inline bool isutf(char c) {
+    return ((c & 0xC0) != 0x80);
+}
+
+/* reads the next utf-8 sequence out of a string, updating an index */
+inline uint32_t u8_nextchar(const char *s, int *i)
+{
+    uint32_t ch = 0;
+    int sz = 0;
+
+    do {
+        ch <<= 6;
+        ch += (unsigned char)s[(*i)++];
+        sz++;
+    } while (s[*i] && !isutf(s[*i]));
+    ch -= offsetsFromUTF8[sz-1];
+
+    return ch;
+}
+
+/* number of characters */
+inline uint64_t u8_strlen(const char *s)
+{
+    static const int maxLength = std::numeric_limits<int>::max();
+
+    uint64_t count = 0;
+    int i = 0;
+
+    while (s[i] != 0 && u8_nextchar(s, &i) != 0) {
+        if (i == maxLength) {
+            throw std::runtime_error(
+                    "String exceeded maximum size of " +
+                    std::to_string(maxLength) + " bytes.");
+        }
+        count++;
+    }
+
+    return count;
+}
+
+}  // namespace utils
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/validation_results.hpp b/examples/validator/valijson/include/valijson/validation_results.hpp
new file mode 100644
index 0000000..3fdc6dd
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/validation_results.hpp
@@ -0,0 +1,126 @@
+#pragma once
+#ifndef __VALIJSON_VALIDATION_RESULTS_HPP
+#define __VALIJSON_VALIDATION_RESULTS_HPP
+
+#include <deque>
+#include <string>
+#include <vector>
+
+namespace valijson {
+
+/**
+ * @brief  Class that encapsulates the storage of validation errors.
+ *
+ * This class maintains an internal FIFO queue of errors that are reported
+ * during validation. Errors are pushed on to the back of an internal
+ * queue, and can retrieved by popping them from the front of the queue.
+ */
+class ValidationResults
+{
+public:
+
+    /**
+     * @brief  Describes a validation error.
+     *
+     * This struct is used to pass around the context and description of a
+     * validation error.
+     */
+    struct Error
+    {
+        /**
+         * @brief  Construct an Error object with no context or description.
+         */
+        Error() { }
+
+        /**
+         * @brief  Construct an Error object using a context and description.
+         *
+         * @param  context      Context string to use
+         * @param  description  Description string to use
+         */
+        Error(const std::vector<std::string> &context, const std::string &description)
+          : context(context),
+            description(description) { }
+
+        /// Path to the node that failed validation.
+        std::vector<std::string> context;
+
+        /// A detailed description of the validation error.
+        std::string description;
+    };
+
+    /**
+     * @brief  Return begin iterator for results in the queue.
+     */
+    std::deque<Error>::const_iterator begin() const
+    {
+        return errors.begin();
+    }
+
+    /**
+     * @brief  Return end iterator for results in the queue.
+     */
+    std::deque<Error>::const_iterator end() const
+    {
+        return errors.end();
+    }
+
+    /**
+     * @brief  Return the number of errors in the queue.
+     */
+    size_t numErrors() const
+    {
+        return errors.size();
+    }
+
+    /**
+     * @brief  Copy an Error and push it on to the back of the queue.
+     *
+     * @param  error  Reference to an Error object to be copied.
+     */
+    void pushError(const Error &error)
+    {
+        errors.push_back(error);
+    }
+
+    /**
+     * @brief  Push an error onto the back of the queue.
+     *
+     * @param  context      Context of the validation error.
+     * @param  description  Description of the validation error.
+     */
+    void
+    pushError(const std::vector<std::string> &context, const std::string &description)
+    {
+        errors.push_back(Error(context, description));
+    }
+
+    /**
+     * @brief  Pop an error from the front of the queue.
+     *
+     * @param  error  Reference to an Error object to populate.
+     *
+     * @returns  true if an Error was popped, false otherwise.
+     */
+    bool
+    popError(Error &error)
+    {
+        if (errors.empty()) {
+            return false;
+        }
+
+        error = errors.front();
+        errors.pop_front();
+        return true;
+    }
+
+private:
+
+    /// FIFO queue of validation errors that have been reported
+    std::deque<Error> errors;
+
+};
+
+} // namespace valijson
+
+#endif // __VALIJSON_VALIDATION_RESULTS_HPP
diff --git a/examples/validator/valijson/include/valijson/validation_visitor.hpp b/examples/validator/valijson/include/valijson/validation_visitor.hpp
new file mode 100644
index 0000000..548bd28
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/validation_visitor.hpp
@@ -0,0 +1,1706 @@
+#pragma once
+#ifndef __VALIJSON_VALIDATION_VISITOR_HPP
+#define __VALIJSON_VALIDATION_VISITOR_HPP
+
+#include <cmath>
+#include <string>
+#include <regex>
+
+#include <valijson/constraints/concrete_constraints.hpp>
+#include <valijson/constraints/constraint_visitor.hpp>
+#include <valijson/validation_results.hpp>
+
+#include <valijson/utils/utf8_utils.hpp>
+
+namespace valijson {
+
+class ValidationResults;
+
+/**
+ * @brief   Implementation of the ConstraintVisitor interface that validates a
+ *          target document
+ *
+ * @tparam  AdapterType  Adapter type for the target document.
+ */
+template<typename AdapterType>
+class ValidationVisitor: public constraints::ConstraintVisitor
+{
+public:
+
+    /**
+     * @brief  Construct a new validator for a given target value and context.
+     *
+     * @param  target       Target value to be validated
+     * @param  context      Current context for validation error descriptions,
+     *                      only used if results is set.
+     * @param  strictTypes  Use strict type comparison
+     * @param  results      Optional pointer to ValidationResults object, for
+     *                      recording error descriptions. If this pointer is set
+     *                      to NULL, validation errors will caused validation to
+     *                      stop immediately.
+     */
+    ValidationVisitor(const AdapterType &target,
+                      const std::vector<std::string> &context,
+                      const bool strictTypes,
+                      ValidationResults *results)
+      : target(target),
+        context(context),
+        results(results),
+        strictTypes(strictTypes) { }
+
+    /**
+     * @brief  Validate the target against a schema.
+     *
+     * When a ValidationResults object has been set via the 'results' member
+     * variable, validation will proceed as long as no fatal errors occur,
+     * with error descriptions added to the ValidationResults object.
+     *
+     * If a pointer to a ValidationResults instance is not provided, validation
+     * will only continue for as long as the constraints are validated
+     * successfully.
+     *
+     * @param   subschema  Sub-schema that the target must validate against
+     *
+     * @return  \c true if validation passes; \c false otherwise
+     */
+    bool validateSchema(const Subschema &subschema)
+    {
+        // Wrap the validationCallback() function below so that it will be
+        // passed a reference to a constraint (_1), and a reference to the
+        // visitor (*this).
+        Subschema::ApplyFunction fn(std::bind(validationCallback, std::placeholders::_1, *this));
+
+        // Perform validation against each constraint defined in the schema
+        if (results == NULL) {
+            // The applyStrict() function will return immediately if the
+            // callback function returns false
+            if (!subschema.applyStrict(fn)) {
+                return false;
+            }
+        } else {
+            // The apply() function will iterate over all constraints in the
+            // schema, even if the callback function returns false. Once
+            // iteration is complete, the apply() function will return true
+            // only if all invokations of the callback function returned true.
+            if (!subschema.apply(fn)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief  Validate a value against an AllOfConstraint
+     *
+     * An allOf constraint provides a set of child schemas against which the
+     * target must be validated in order for the constraint to the satifisfied.
+     *
+     * When a ValidationResults object has been set via the 'results' member
+     * variable, validation will proceed as long as no fatal errors occur,
+     * with error descriptions added to the ValidationResults object.
+     *
+     * If a pointer to a ValidationResults instance is not provided, validation
+     * will only continue for as long as the child schemas are validated
+     * successfully.
+     *
+     * @param  constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if validation passes; \c false otherwise
+     */
+    virtual bool visit(const AllOfConstraint &constraint)
+    {
+        bool validated = true;
+
+        constraint.applyToSubschemas(ValidateSubschemas(target, context,
+                true, false, *this, results, NULL, &validated));
+
+        return validated;
+    }
+
+    /**
+     * @brief   Validate a value against an AnyOfConstraint
+     *
+     * An anyOf constraint provides a set of child schemas, any of which the
+     * target may be validated against in order for the constraint to the
+     * satifisfied.
+     *
+     * Because an anyOf constraint does not require the target to validate
+     * against all child schemas, if validation against a single schema fails,
+     * the results will not be added to a ValidationResults object. Only if
+     * validation fails for all child schemas will an error be added to the
+     * ValidationResults object.
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if validation passes; \c false otherwise
+     */
+    virtual bool visit(const AnyOfConstraint &constraint)
+    {
+        unsigned int numValidated = 0;
+
+        ValidationResults newResults;
+        ValidationResults *childResults = (results) ? &newResults : NULL;
+
+        ValidationVisitor<AdapterType> v(target, context, strictTypes, childResults);
+        constraint.applyToSubschemas(ValidateSubschemas(target, context, false,
+                true, v, childResults, &numValidated, NULL));
+
+        if (numValidated == 0 && results) {
+            ValidationResults::Error childError;
+            while (childResults->popError(childError)) {
+                results->pushError(
+                        childError.context,
+                        childError.description);
+            }
+            results->pushError(context, "Failed to validate against any child "
+                    "schemas allowed by anyOf constraint.");
+        }
+
+        return numValidated > 0;
+    }
+
+    /**
+     * @brief   Validate current node against a 'dependencies' constraint
+     *
+     * A 'dependencies' constraint can be used to specify property-based or
+     * schema-based dependencies that must be fulfilled when a particular
+     * property is present in an object.
+     *
+     * Property-based dependencies define a set of properties that must be
+     * present in addition to a particular property, whereas a schema-based
+     * dependency defines an additional schema that the current document must
+     * validate against.
+     *
+     * @param   constraint  DependenciesConstraint that the current node
+     *                      must validate against
+     *
+     * @return  \c true if validation passes; \c false otherwise
+     */
+    virtual bool visit(const DependenciesConstraint &constraint)
+    {
+        // Ignore non-objects
+        if ((strictTypes && !target.isObject()) || (!target.maybeObject())) {
+            return true;
+        }
+
+        // Object to be validated
+        const typename AdapterType::Object object = target.asObject();
+
+        // Cleared if validation fails
+        bool validated = true;
+
+        // Iterate over all dependent properties defined by this constraint,
+        // invoking the DependentPropertyValidator functor once for each
+        // set of dependent properties
+        constraint.applyToPropertyDependencies(ValidatePropertyDependencies(
+                object, context, results, &validated));
+        if (!results && !validated) {
+            return false;
+        }
+
+        // Iterate over all dependent schemas defined by this constraint,
+        // invoking the DependentSchemaValidator function once for each schema
+        // that must be validated if a given property is present
+        constraint.applyToSchemaDependencies(ValidateSchemaDependencies(
+                object, context, *this, results, &validated));
+        if (!results && !validated) {
+            return false;
+        }
+
+        return validated;
+    }
+
+    /**
+     * @brief   Validate current node against an EnumConstraint
+     *
+     * Validation succeeds if the target is equal to one of the values provided
+     * by the EnumConstraint.
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if validation succeeds; \c false otherwise
+     */
+    virtual bool visit(const EnumConstraint &constraint)
+    {
+        unsigned int numValidated = 0;
+        constraint.applyToValues(ValidateEquality(target, context, false, true,
+                strictTypes, NULL, &numValidated));
+
+        if (numValidated == 0) {
+            if (results) {
+                results->pushError(context,
+                        "Failed to match against any enum values.");
+            }
+
+            return false;
+        }
+
+        return numValidated > 0;
+    }
+
+    /**
+     * @brief   Validate a value against a LinearItemsConstraint
+     
+     * A LinearItemsConstraint represents an 'items' constraint that specifies,
+     * for each item in array, an individual sub-schema that the item must
+     * validate against. The LinearItemsConstraint class also captures the
+     * presence of an 'additionalItems' constraint, which specifies a default
+     * sub-schema that should be used if an array contains more items than
+     * there are sub-schemas in the 'items' constraint.
+     *
+     * If the current value is not an array, validation always succeeds.
+     *
+     * @param  constraint  SingularItemsConstraint to validate against
+     *
+     * @returns  \c true if validation is successful; \c false otherwise
+     */
+    virtual bool visit(const LinearItemsConstraint &constraint)
+    {
+        // Ignore values that are not arrays
+        if ((strictTypes && !target.isArray()) || (!target.maybeArray())) {
+            return true;
+        }
+
+        // Sub-schema to validate against when number of items in array exceeds
+        // the number of sub-schemas provided by the 'items' constraint
+        const Subschema * const additionalItemsSubschema =
+                constraint.getAdditionalItemsSubschema();
+
+        // Track how many items are validated using 'items' constraint
+        unsigned int numValidated = 0;
+
+        // Array to validate
+        const typename AdapterType::Array arr = target.asArray();
+        const size_t arrSize = arr.size();
+
+        // Track validation status
+        bool validated = true;
+
+        // Validate as many items as possible using 'items' sub-schemas
+        const size_t itemSubschemaCount = constraint.getItemSubschemaCount();
+        if (itemSubschemaCount > 0) {
+            if (!additionalItemsSubschema) {
+                if (arrSize > itemSubschemaCount) {
+                    if (results) {
+                        results->pushError(context,
+                                "Array contains more items than allowed by "
+                                "items constraint.");
+                        validated = false;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+
+            constraint.applyToItemSubschemas(ValidateItems(arr, context, true,
+                    results != NULL, strictTypes, results, &numValidated,
+                    &validated));
+
+            if (!results && !validated) {
+                return false;
+            }
+        }
+
+        // Validate remaining items using 'additionalItems' sub-schema
+        if (numValidated < arrSize) {
+            if (additionalItemsSubschema) {
+                // Begin validation from the first item not validated against
+                // an sub-schema provided by the 'items' constraint
+                unsigned int index = numValidated;
+                typename AdapterType::Array::const_iterator begin = arr.begin();
+                begin.advance(numValidated);
+                for (typename AdapterType::Array::const_iterator itr = begin;
+                        itr != arr.end(); ++itr) {
+
+                    // Update context for current array item
+                    std::vector<std::string> newContext = context;
+                    newContext.push_back("[" +
+                            std::to_string(index) + "]");
+
+                    ValidationVisitor<AdapterType> validator(*itr, newContext,
+                            strictTypes, results);
+
+                    if (!validator.validateSchema(*additionalItemsSubschema)) {
+                        if (results) {
+                            results->pushError(context,
+                                    "Failed to validate item #" +
+                                    std::to_string(index) +
+                                    " against additional items schema.");
+                            validated = false;
+                        } else {
+                            return false;
+                        }
+                    }
+
+                    index++;
+                }
+
+            } else if (results) {
+                results->pushError(context, "Cannot validate item #" +
+                    std::to_string(numValidated) + " or "
+                    "greater using 'items' constraint or 'additionalItems' "
+                    "constraint.");
+                validated = false;
+
+            } else {
+                return false;
+            }
+        }
+
+        return validated;
+    }
+
+    /**
+     * @brief   Validate a value against a MaximumConstraint object
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if constraints are satisfied; \c false otherwise
+     */
+    virtual bool visit(const MaximumConstraint &constraint)
+    {
+        if ((strictTypes && !target.isNumber()) || !target.maybeDouble()) {
+            // Ignore values that are not numbers
+            return true;
+        }
+
+        const double maximum = constraint.getMaximum();
+
+        if (constraint.getExclusiveMaximum()) {
+            if (target.asDouble() >= maximum) {
+                if (results) {
+                    results->pushError(context, "Expected number less than " +
+                            std::to_string(maximum));
+                }
+
+                return false;
+            }
+
+        } else if (target.asDouble() > maximum) {
+            if (results) {
+                results->pushError(context,
+                        "Expected number less than or equal to " +
+                        std::to_string(maximum));
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a MaxItemsConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MaxItemsConstraint &constraint)
+    {
+        if ((strictTypes && !target.isArray()) || !target.maybeArray()) {
+            return true;
+        }
+
+        const uint64_t maxItems = constraint.getMaxItems();
+        if (target.asArray().size() <= maxItems) {
+            return true;
+        }
+
+        if (results) {
+            results->pushError(context, "Array should contain no more than " +
+                    std::to_string(maxItems) + " elements.");
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate a value against a MaxLengthConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MaxLengthConstraint &constraint)
+    {
+        if ((strictTypes && !target.isString()) || !target.maybeString()) {
+            return true;
+        }
+
+        const std::string s = target.asString();
+        const uint64_t len = utils::u8_strlen(s.c_str());
+        const uint64_t maxLength = constraint.getMaxLength();
+        if (len <= maxLength) {
+            return true;
+        }
+
+        if (results) {
+            results->pushError(context,
+                    "String should be no more than " +
+                    std::to_string(maxLength) +
+                    " characters in length.");
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate a value against a MaxPropertiesConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MaxPropertiesConstraint &constraint)
+    {
+        if ((strictTypes && !target.isObject()) || !target.maybeObject()) {
+            return true;
+        }
+
+        const uint64_t maxProperties = constraint.getMaxProperties();
+
+        if (target.asObject().size() <= maxProperties) {
+            return true;
+        }
+
+        if (results) {
+            results->pushError(context, "Object should have no more than " +
+                    std::to_string(maxProperties) +
+                    " properties.");
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate a value against a MinimumConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MinimumConstraint &constraint)
+    {
+        if ((strictTypes && !target.isNumber()) || !target.maybeDouble()) {
+            // Ignore values that are not numbers
+            return true;
+        }
+
+        const double minimum = constraint.getMinimum();
+
+        if (constraint.getExclusiveMinimum()) {
+            if (target.asDouble() <= minimum) {
+                if (results) {
+                    results->pushError(context,
+                        "Expected number greater than " +
+                        std::to_string(minimum));
+                }
+
+                return false;
+            }
+        } else if (target.asDouble() < minimum) {
+            if (results) {
+                results->pushError(context,
+                        "Expected number greater than or equal to " +
+                        std::to_string(minimum));
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a MinItemsConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MinItemsConstraint &constraint)
+    {
+        if ((strictTypes && !target.isArray()) || !target.maybeArray()) {
+            return true;
+        }
+
+        const uint64_t minItems = constraint.getMinItems();
+        if (target.asArray().size() >= minItems) {
+            return true;
+        }
+
+        if (results) {
+            results->pushError(context, "Array should contain no fewer than " +
+                std::to_string(minItems) + " elements.");
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate a value against a MinLengthConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MinLengthConstraint &constraint)
+    {
+        if ((strictTypes && !target.isString()) || !target.maybeString()) {
+            return true;
+        }
+
+        const std::string s = target.asString();
+        const uint64_t len = utils::u8_strlen(s.c_str());
+        const uint64_t minLength = constraint.getMinLength();
+        if (len >= minLength) {
+            return true;
+        }
+
+        if (results) {
+            results->pushError(context,
+                    "String should be no fewer than " +
+                    std::to_string(minLength) +
+                    " characters in length.");
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate a value against a MinPropertiesConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MinPropertiesConstraint &constraint)
+    {
+        if ((strictTypes && !target.isObject()) || !target.maybeObject()) {
+            return true;
+        }
+
+        const uint64_t minProperties = constraint.getMinProperties();
+
+        if (target.asObject().size() >= minProperties) {
+            return true;
+        }
+
+        if (results) {
+            results->pushError(context, "Object should have no fewer than " +
+                    std::to_string(minProperties) +
+                    " properties.");
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate a value against a MultipleOfDoubleConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MultipleOfDoubleConstraint &constraint)
+    {
+        const double divisor = constraint.getDivisor();
+
+        double d = 0.;
+        if (target.maybeDouble()) {
+            if (!target.asDouble(d)) {
+                if (results) {
+                    results->pushError(context, "Value could not be converted "
+                        "to a number to check if it is a multiple of " +
+                        std::to_string(divisor));
+                }
+                return false;
+            }
+        } else if (target.maybeInteger()) {
+            int64_t i = 0;
+            if (!target.asInteger(i)) {
+                if (results) {
+                    results->pushError(context, "Value could not be converted "
+                        "to a number to check if it is a multiple of " +
+                        std::to_string(divisor));
+                }
+                return false;
+            }
+            d = static_cast<double>(i);
+        } else {
+            return true;
+        }
+
+        if (d == 0) {
+            return true;
+        }
+
+        const double r = remainder(d, divisor);
+
+        if (fabs(r) > std::numeric_limits<double>::epsilon()) {
+            if (results) {
+                results->pushError(context, "Value should be a multiple of " +
+                    std::to_string(divisor));
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a MultipleOfIntConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const MultipleOfIntConstraint &constraint)
+    {
+        const int64_t divisor = constraint.getDivisor();
+
+        int64_t i = 0;
+        if (target.maybeInteger()) {
+            if (!target.asInteger(i)) {
+                if (results) {
+                    results->pushError(context, "Value could not be converted "
+                        "to an integer for multipleOf check");
+                }
+                return false;
+            }
+        } else if (target.maybeDouble()) {
+            double d;
+            if (!target.asDouble(d)) {
+                if (results) {
+                    results->pushError(context, "Value could not be converted "
+                        "to a double for multipleOf check");
+                }
+                return false;
+            }
+            i = static_cast<int64_t>(d);
+        } else {
+            return true;
+        }
+
+        if (i == 0) {
+            return true;
+        }
+
+        if (i % divisor != 0) {
+            if (results) {
+                results->pushError(context, "Value should be a multiple of " +
+                    std::to_string(divisor));
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a NotConstraint
+     *
+     * If the subschema NotConstraint currently holds a NULL pointer, the
+     * schema will be treated like the empty schema. Therefore validation
+     * will always fail.
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const NotConstraint &constraint)
+    {
+        const Subschema *subschema = constraint.getSubschema();
+        if (!subschema) {
+            // Treat NULL pointer like empty schema
+            return false;
+        }
+
+        ValidationVisitor<AdapterType> v(target, context, strictTypes, NULL);
+        if (v.validateSchema(*subschema)) {
+            if (results) {
+                results->pushError(context,
+                        "Target should not validate against schema "
+                        "specified in 'not' constraint.");
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a OneOfConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const OneOfConstraint &constraint)
+    {
+        unsigned int numValidated = 0;
+
+        ValidationResults newResults;
+        ValidationResults *childResults = (results) ? &newResults : NULL;
+
+        ValidationVisitor<AdapterType> v(target, context, strictTypes, childResults);
+        constraint.applyToSubschemas(ValidateSubschemas(target, context,
+                true, true, v, childResults, &numValidated, NULL));
+
+        if (numValidated == 0) {
+            if (results) {
+                ValidationResults::Error childError;
+                while (childResults->popError(childError)) {
+                    results->pushError(
+                            childError.context,
+                            childError.description);
+                }
+                results->pushError(context, "Failed to validate against any "
+                        "child schemas allowed by oneOf constraint.");
+            }
+            return false;
+        } else if (numValidated != 1) {
+            if (results) {
+                results->pushError(context,
+                        "Failed to validate against exactly one child schema.");
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a PatternConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const PatternConstraint &constraint)
+    {
+        if ((strictTypes && !target.isString()) || !target.maybeString()) {
+            return true;
+        }
+
+        const std::regex patternRegex(
+                constraint.getPattern<std::string::allocator_type>());
+
+        if (!std::regex_search(target.asString(), patternRegex)) {
+            if (results) {
+                results->pushError(context,
+                        "Failed to match regex specified by 'pattern' "
+                        "constraint.");
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @brief   Validate a value against a PatternConstraint
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const constraints::PolyConstraint &constraint)
+    {
+        return constraint.validate(target, context, results);
+    }
+
+    /**
+     * @brief   Validate a value against a PropertiesConstraint
+     *
+     * Validation of an object against a PropertiesConstraint proceeds in three
+     * stages. The first stage finds all properties in the object that have a
+     * corresponding subschema in the constraint, and validates those properties
+     * recursively.
+     *
+     * Next, the object's properties will be validated against the subschemas
+     * for any 'patternProperties' that match a given property name. A property
+     * is required to validate against the sub-schema for all patterns that it
+     * matches.
+     *
+     * Finally, any properties that have not yet been validated against at least
+     * one subschema will be validated against the 'additionalItems' subschema.
+     * If this subschema is not present, then all properties must have been
+     * validated at least once.
+     *
+     * Non-object values are always considered valid.
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if the constraint is satisfied; \c false otherwise
+     */
+    virtual bool visit(const PropertiesConstraint &constraint)
+    {
+        if ((strictTypes && !target.isObject()) || !target.maybeObject()) {
+            return true;
+        }
+
+        bool validated = true;
+
+        // Track which properties have already been validated
+        std::set<std::string> propertiesMatched;
+
+        // Validate properties against subschemas for matching 'properties'
+        // constraints
+        const typename AdapterType::Object object = target.asObject();
+        constraint.applyToProperties(ValidatePropertySubschemas(object, context,
+                true, results != NULL, true, strictTypes, results,
+                &propertiesMatched, &validated));
+
+        // Exit early if validation failed, and we're not collecting exhaustive
+        // validation results
+        if (!validated && !results) {
+            return false;
+        }
+
+        // Validate properties against subschemas for matching patternProperties
+        // constraints
+        constraint.applyToPatternProperties(ValidatePatternPropertySubschemas(
+                object, context, true, false, true, strictTypes, results,
+                &propertiesMatched, &validated));
+
+        // Validate against additionalProperties subschema for any properties
+        // that have not yet been matched
+        const Subschema *additionalPropertiesSubschema =
+                constraint.getAdditionalPropertiesSubschema();
+        if (!additionalPropertiesSubschema) {
+            if (propertiesMatched.size() != target.getObjectSize()) {
+                if (results) {
+                    results->pushError(context, "Object contains properties "
+                            "that could not be validated using 'properties' "
+                            "or 'additionalProperties' constraints");
+                }
+
+                return false;
+            }
+
+            return validated;
+        }
+
+        for (const typename AdapterType::ObjectMember m : object) {
+            if (propertiesMatched.find(m.first) == propertiesMatched.end()) {
+                // Update context
+                std::vector<std::string> newContext = context;
+                newContext.push_back("[" + m.first + "]");
+
+                // Create a validator to validate the property's value
+                ValidationVisitor validator(m.second, newContext, strictTypes,
+                        results);
+                if (!validator.validateSchema(*additionalPropertiesSubschema)) {
+                    if (results) {
+                        results->pushError(context, "Failed to validate "
+                                "against additional properties schema");
+                    }
+
+                    validated = false;
+                }
+            }
+        }
+
+        return validated;
+    }
+
+    /**
+     * @brief   Validate a value against a RequiredConstraint
+     *
+     * A required constraint specifies a list of properties that must be present
+     * in the target.
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  \c true if validation succeeds; \c false otherwise
+     */
+    virtual bool visit(const RequiredConstraint &constraint)
+    {
+        if ((strictTypes && !target.isObject()) || !target.maybeObject()) {
+            if (results) {
+                results->pushError(context,
+                        "Object required to validate 'required' properties.");
+            }
+            return false;
+        }
+
+        bool validated = true;
+        const typename AdapterType::Object object = target.asObject();
+        constraint.applyToRequiredProperties(ValidateProperties(object, context,
+                true, results != NULL, results, &validated));
+
+        return validated;
+    }
+
+    /**
+     * @brief  Validate a value against a SingularItemsConstraint
+     *
+     * A SingularItemsConstraint represents an 'items' constraint that specifies
+     * a sub-schema against which all items in an array must validate. If the
+     * current value is not an array, validation always succeeds.
+     *
+     * @param  constraint  SingularItemsConstraint to validate against
+     *
+     * @returns  \c true if validation is successful; \c false otherwise
+     */
+    virtual bool visit(const SingularItemsConstraint &constraint)
+    {
+        // Ignore values that are not arrays
+        if (!target.isArray()) {
+            return true;
+        }
+
+        // Schema against which all items must validate
+        const Subschema *itemsSubschema = constraint.getItemsSubschema();
+
+        // Default items sub-schema accepts all values
+        if (!itemsSubschema) {
+            return true;
+        }
+
+        // Track whether validation has failed
+        bool validated = true;
+
+        unsigned int index = 0;
+        for (const AdapterType &item : target.getArray()) {
+            // Update context for current array item
+            std::vector<std::string> newContext = context;
+            newContext.push_back("[" +
+                    std::to_string(index) + "]");
+
+            // Create a validator for the current array item
+            ValidationVisitor<AdapterType> validationVisitor(item,
+                    newContext, strictTypes, results);
+
+            // Perform validation
+            if (!validationVisitor.validateSchema(*itemsSubschema)) {
+                if (results) {
+                    results->pushError(context,
+                            "Failed to validate item #" +
+                            std::to_string(index) +
+                            " in array.");
+                    validated = false;
+                } else {
+                    return false;
+                }
+            }
+
+            index++;
+        }
+
+        return validated;
+    }
+
+    /**
+     * @brief   Validate a value against a TypeConstraint
+     *
+     * Checks that the target is one of the valid named types, or matches one
+     * of a set of valid sub-schemas.
+     *
+     * @param   constraint  TypeConstraint to validate against
+     *
+     * @return  \c true if validation is successful; \c false otherwise
+     */
+    virtual bool visit(const TypeConstraint &constraint)
+    {
+        // Check named types
+        {
+            // ValidateNamedTypes functor assumes target is invalid
+            bool validated = false;
+            constraint.applyToNamedTypes(ValidateNamedTypes(target, false,
+                    true, strictTypes, &validated));
+            if (validated) {
+                return true;
+            }
+        }
+
+        // Check schema-based types
+        {
+            unsigned int numValidated = 0;
+            constraint.applyToSchemaTypes(ValidateSubschemas(target, context,
+                    false, true, *this, NULL, &numValidated, NULL));
+            if (numValidated > 0) {
+                return true;
+            } else if (results) {
+                results->pushError(context,
+                        "Value type not permitted by 'type' constraint.");
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @brief   Validate the uniqueItems constraint represented by a
+     *          UniqueItems object.
+     *
+     * A uniqueItems constraint requires that each of the values in an array
+     * are unique. Comparison is performed recursively.
+     *
+     * @param   constraint  Constraint that the target must validate against
+     *
+     * @return  true if validation succeeds, false otherwise
+     */
+    virtual bool visit(const UniqueItemsConstraint &)
+    {
+        if ((strictTypes && !target.isArray()) || !target.maybeArray()) {
+            return true;
+        }
+
+        // Empty arrays are always valid
+        if (target.getArraySize() == 0) {
+            return true;
+        }
+
+        const typename AdapterType::Array targetArray = target.asArray();
+        const typename AdapterType::Array::const_iterator end = targetArray.end();
+
+        bool validated = true;
+        const typename AdapterType::Array::const_iterator secondLast = --targetArray.end();
+        unsigned int outerIndex = 0;
+        typename AdapterType::Array::const_iterator outerItr = targetArray.begin();
+        for (; outerItr != secondLast; ++outerItr) {
+            unsigned int innerIndex = outerIndex + 1;
+            typename AdapterType::Array::const_iterator innerItr(outerItr);
+            for (++innerItr; innerItr != end; ++innerItr) {
+                if (outerItr->equalTo(*innerItr, true)) {
+                    if (results) {
+                        results->pushError(context, "Elements at indexes #" +
+                            std::to_string(outerIndex) + " and #" +
+                            std::to_string(innerIndex) + " violate uniqueness constraint.");
+                        validated = false;
+                    } else {
+                        return false;
+                    }
+                }
+                ++innerIndex;
+            }
+            ++outerIndex;
+        }
+
+        return validated;
+    }
+
+private:
+
+    /**
+     * @brief  Functor to compare a node with a collection of values
+     */
+    struct ValidateEquality
+    {
+        ValidateEquality(
+                const AdapterType &target,
+                const std::vector<std::string> &context,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                bool strictTypes,
+                ValidationResults *results,
+                unsigned int *numValidated)
+          : target(target),
+            context(context),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            strictTypes(strictTypes),
+            results(results),
+            numValidated(numValidated) { }
+
+        template<typename OtherValue>
+        bool operator()(const OtherValue &value) const
+        {
+            if (value.equalTo(target, strictTypes)) {
+                if (numValidated) {
+                    (*numValidated)++;
+                }
+
+                return continueOnSuccess;
+            }
+
+            if (results) {
+                results->pushError(context,
+                        "Target value and comparison value are not equal");
+            }
+
+            return continueOnFailure;
+        }
+
+    private:
+        const AdapterType &target;
+        const std::vector<std::string> &context;
+        bool continueOnSuccess;
+        bool continueOnFailure;
+        bool strictTypes;
+        ValidationResults * const results;
+        unsigned int * const numValidated;
+    };
+
+    /**
+     * @brief  Functor to validate the presence of a set of properties
+     */
+    struct ValidateProperties
+    {
+        ValidateProperties(
+                const typename AdapterType::Object &object,
+                const std::vector<std::string> &context,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                ValidationResults *results,
+                bool *validated)
+          : object(object),
+            context(context),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            results(results),
+            validated(validated) { }
+
+        template<typename StringType>
+        bool operator()(const StringType &property) const
+        {
+            if (object.find(property.c_str()) == object.end()) {
+                if (validated) {
+                    *validated = false;
+                }
+
+                if (results) {
+                    results->pushError(context, "Missing required property '" +
+                            std::string(property.c_str()) + "'.");
+                }
+
+                return continueOnFailure;
+            }
+
+            return continueOnSuccess;
+        }
+
+    private:
+        const typename AdapterType::Object &object;
+        const std::vector<std::string> &context;
+        bool continueOnSuccess;
+        bool continueOnFailure;
+        ValidationResults * const results;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Functor to validate property-based dependencies
+     */
+    struct ValidatePropertyDependencies
+    {
+        ValidatePropertyDependencies(
+                const typename AdapterType::Object &object,
+                const std::vector<std::string> &context,
+                ValidationResults *results,
+                bool *validated)
+          : object(object),
+            context(context),
+            results(results),
+            validated(validated) { }
+
+        template<typename StringType, typename ContainerType>
+        bool operator()(
+                const StringType &propertyName,
+                const ContainerType &dependencyNames) const
+        {
+            const std::string propertyNameKey(propertyName.c_str());
+            if (object.find(propertyNameKey) == object.end()) {
+                return true;
+            }
+
+            typedef typename ContainerType::value_type ValueType;
+            for (const ValueType &dependencyName : dependencyNames) {
+                const std::string dependencyNameKey(dependencyName.c_str());
+                if (object.find(dependencyNameKey) == object.end()) {
+                    if (validated) {
+                        *validated = false;
+                    }
+                    if (results) {
+                        results->pushError(context, "Missing dependency '" +
+                                dependencyNameKey + "'.");
+                    } else {
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+
+    private:
+        const typename AdapterType::Object &object;
+        const std::vector<std::string> &context;
+        ValidationResults * const results;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Functor to validate against sub-schemas in 'items' constraint
+     */
+    struct ValidateItems
+    {
+        ValidateItems(
+                const typename AdapterType::Array &arr,
+                const std::vector<std::string> &context,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                bool strictTypes,
+                ValidationResults *results,
+                unsigned int *numValidated,
+                bool *validated)
+          : arr(arr),
+            context(context),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            strictTypes(strictTypes),
+            results(results),
+            numValidated(numValidated),
+            validated(validated) { }
+
+        bool operator()(unsigned int index, const Subschema *subschema) const
+        {
+            // Check that there are more elements to validate
+            if (index >= arr.size()) {
+                return false;
+            }
+
+            // Update context
+            std::vector<std::string> newContext = context;
+            newContext.push_back(
+                    "[" + std::to_string(index) + "]");
+
+            // Find array item
+            typename AdapterType::Array::const_iterator itr = arr.begin();
+            itr.advance(index);
+
+            // Validate current array item
+            ValidationVisitor validator(*itr, newContext, strictTypes, results);
+            if (validator.validateSchema(*subschema)) {
+                if (numValidated) {
+                    (*numValidated)++;
+                }
+
+                return continueOnSuccess;
+            }
+
+            if (validated) {
+                *validated = false;
+            }
+
+            if (results) {
+                results->pushError(newContext,
+                    "Failed to validate item #" +
+                    std::to_string(index) +
+                    " against corresponding item schema.");
+            }
+
+            return continueOnFailure;
+        }
+
+    private:
+        const typename AdapterType::Array &arr;
+        const std::vector<std::string> &context;
+        bool continueOnSuccess;
+        bool continueOnFailure;
+        bool strictTypes;
+        ValidationResults * const results;
+        unsigned int * const numValidated;
+        bool * const validated;
+
+    };
+
+    /**
+     * @brief  Functor to validate value against named JSON types
+     */
+    struct ValidateNamedTypes
+    {
+        ValidateNamedTypes(
+                const AdapterType &target,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                bool strictTypes,
+                bool *validated)
+          : target(target),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            strictTypes(strictTypes),
+            validated(validated) { }
+
+        bool operator()(constraints::TypeConstraint::JsonType jsonType) const
+        {
+            typedef constraints::TypeConstraint TypeConstraint;
+
+            bool valid = false;
+
+            switch (jsonType) {
+            case TypeConstraint::kAny:
+                valid = true;
+                break;
+            case TypeConstraint::kArray:
+                valid = target.isArray();
+                break;
+            case TypeConstraint::kBoolean:
+                valid = target.isBool() || (!strictTypes && target.maybeBool());
+                break;
+            case TypeConstraint::kInteger:
+                valid = target.isInteger() ||
+                        (!strictTypes && target.maybeInteger());
+                break;
+            case TypeConstraint::kNull:
+                valid = target.isNull() ||
+                        (!strictTypes && target.maybeNull());
+                break;
+            case TypeConstraint::kNumber:
+                valid = target.isNumber() ||
+                        (!strictTypes && target.maybeDouble());
+                break;
+            case TypeConstraint::kObject:
+                valid = target.isObject();
+                break;
+            case TypeConstraint::kString:
+                valid = target.isString();
+                break;
+            default:
+                break;
+            }
+
+            if (valid && validated) {
+                *validated = true;
+            }
+
+            return (valid && continueOnSuccess) || continueOnFailure;
+        }
+
+    private:
+        const AdapterType target;
+        const bool continueOnSuccess;
+        const bool continueOnFailure;
+        const bool strictTypes;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Functor to validate object properties against sub-schemas
+     *         defined by a 'patternProperties' constraint
+     */
+    struct ValidatePatternPropertySubschemas
+    {
+        ValidatePatternPropertySubschemas(
+                const typename AdapterType::Object &object,
+                const std::vector<std::string> &context,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                bool continueIfUnmatched,
+                bool strictTypes,
+                ValidationResults *results,
+                std::set<std::string> *propertiesMatched,
+                bool *validated)
+          : object(object),
+            context(context),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            continueIfUnmatched(continueIfUnmatched),
+            strictTypes(strictTypes),
+            results(results),
+            propertiesMatched(propertiesMatched),
+            validated(validated) { }
+
+        template<typename StringType>
+        bool operator()(const StringType &patternProperty,
+                const Subschema *subschema) const
+        {
+            const std::string patternPropertyStr(patternProperty.c_str());
+
+            // It would be nice to store pre-allocated regex objects in the
+            // PropertiesConstraint. does std::regex currently support
+            // custom allocators? Anyway, this isn't an issue here, because Valijson's
+            // JSON Scheme validator does not yet support custom allocators.
+            const std::regex r(patternPropertyStr);
+
+            bool matchFound = false;
+
+            // Recursively validate all matching properties
+            typedef const typename AdapterType::ObjectMember ObjectMember;
+            for (const ObjectMember m : object) {
+                if (std::regex_search(m.first, r)) {
+                    matchFound = true;
+                    if (propertiesMatched) {
+                        propertiesMatched->insert(m.first);
+                    }
+
+                    // Update context
+                    std::vector<std::string> newContext = context;
+                    newContext.push_back("[" + m.first + "]");
+
+                    // Recursively validate property's value
+                    ValidationVisitor validator(m.second, newContext,
+                            strictTypes, results);
+                    if (validator.validateSchema(*subschema)) {
+                        continue;
+                    }
+
+                    if (results) {
+                        results->pushError(context, "Failed to validate "
+                                "against schema associated with pattern '" +
+                                patternPropertyStr + "'.");
+                    }
+
+                    if (validated) {
+                        *validated = false;
+                    }
+
+                    if (!continueOnFailure) {
+                        return false;
+                    }
+                }
+            }
+
+            // Allow iteration to terminate if there was not at least one match
+            if (!matchFound && !continueIfUnmatched) {
+                return false;
+            }
+
+            return continueOnSuccess;
+        }
+
+    private:
+        const typename AdapterType::Object &object;
+        const std::vector<std::string> &context;
+        const bool continueOnSuccess;
+        const bool continueOnFailure;
+        const bool continueIfUnmatched;
+        const bool strictTypes;
+        ValidationResults * const results;
+        std::set<std::string> * const propertiesMatched;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Functor to validate object properties against sub-schemas defined
+     *         by a 'properties' constraint
+     */
+    struct ValidatePropertySubschemas
+    {
+        ValidatePropertySubschemas(
+                const typename AdapterType::Object &object,
+                const std::vector<std::string> &context,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                bool continueIfUnmatched,
+                bool strictTypes,
+                ValidationResults *results,
+                std::set<std::string> *propertiesMatched,
+                bool *validated)
+          : object(object),
+            context(context),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            continueIfUnmatched(continueIfUnmatched),
+            strictTypes(strictTypes),
+            results(results),
+            propertiesMatched(propertiesMatched),
+            validated(validated) { }
+
+        template<typename StringType>
+        bool operator()(const StringType &propertyName,
+                const Subschema *subschema) const
+        {
+            const std::string propertyNameKey(propertyName.c_str());
+            const typename AdapterType::Object::const_iterator itr =
+                    object.find(propertyNameKey);
+            if (itr == object.end()) {
+                return continueIfUnmatched;
+            }
+
+            if (propertiesMatched) {
+                propertiesMatched->insert(propertyNameKey);
+            }
+
+            // Update context
+            std::vector<std::string> newContext = context;
+            newContext.push_back("[" + propertyNameKey + "]");
+
+            // Recursively validate property's value
+            ValidationVisitor validator(itr->second, newContext, strictTypes,
+                    results);
+            if (validator.validateSchema(*subschema)) {
+                return continueOnSuccess;
+            }
+
+            if (results) {
+                results->pushError(context, "Failed to validate against "
+                        "schema associated with property name '" +
+                        propertyNameKey + "'.");
+            }
+
+            if (validated) {
+                *validated = false;
+            }
+
+            return continueOnFailure;
+        }
+
+    private:
+        const typename AdapterType::Object &object;
+        const std::vector<std::string> &context;
+        const bool continueOnSuccess;
+        const bool continueOnFailure;
+        const bool continueIfUnmatched;
+        const bool strictTypes;
+        ValidationResults * const results;
+        std::set<std::string> * const propertiesMatched;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Functor to validate schema-based dependencies
+     */
+    struct ValidateSchemaDependencies
+    {
+        ValidateSchemaDependencies(
+                const typename AdapterType::Object &object,
+                const std::vector<std::string> &context,
+                ValidationVisitor &validationVisitor,
+                ValidationResults *results,
+                bool *validated)
+          : object(object),
+            context(context),
+            validationVisitor(validationVisitor),
+            results(results),
+            validated(validated) { }
+
+        template<typename StringType>
+        bool operator()(
+                const StringType &propertyName,
+                const Subschema *schemaDependency) const
+        {
+            const std::string propertyNameKey(propertyName.c_str());
+            if (object.find(propertyNameKey) == object.end()) {
+                return true;
+            }
+
+            if (!validationVisitor.validateSchema(*schemaDependency)) {
+                if (validated) {
+                    *validated = false;
+                }
+                if (results) {
+                    results->pushError(context,
+                            "Failed to validate against dependent schema.");
+                } else {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+    private:
+        const typename AdapterType::Object &object;
+        const std::vector<std::string> &context;
+        ValidationVisitor &validationVisitor;
+        ValidationResults * const results;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Functor that can be used to validate one or more subschemas
+     *
+     * This functor is designed to be applied to collections of subschemas
+     * contained within 'allOf', 'anyOf' and 'oneOf' constraints.
+     *
+     * The return value depends on whether a given schema validates, with the
+     * actual return value for a given case being decided at construction time.
+     * The return value is used by the 'applyToSubschemas' functions in the
+     * AllOfConstraint, AnyOfConstraint and OneOfConstrant classes to decide
+     * whether to terminate early.
+     *
+     * The functor uses output parameters (provided at construction) to update
+     * validation state that may be needed by the caller.
+     */
+    struct ValidateSubschemas
+    {
+        ValidateSubschemas(
+                const AdapterType &adapter,
+                const std::vector<std::string> &context,
+                bool continueOnSuccess,
+                bool continueOnFailure,
+                ValidationVisitor &validationVisitor,
+                ValidationResults *results,
+                unsigned int *numValidated,
+                bool *validated)
+          : adapter(adapter),
+            context(context),
+            continueOnSuccess(continueOnSuccess),
+            continueOnFailure(continueOnFailure),
+            validationVisitor(validationVisitor),
+            results(results),
+            numValidated(numValidated),
+            validated(validated) { }
+
+        bool operator()(unsigned int index, const Subschema *subschema) const
+        {
+            if (validationVisitor.validateSchema(*subschema)) {
+                if (numValidated) {
+                    (*numValidated)++;
+                }
+
+                return continueOnSuccess;
+            }
+
+            if (validated) {
+                *validated = false;
+            }
+
+            if (results) {
+                results->pushError(context,
+                        "Failed to validate against child schema #" +
+                                   std::to_string(index) + ".");
+            }
+
+            return continueOnFailure;
+        }
+
+    private:
+        const AdapterType &adapter;
+        const std::vector<std::string> &context;
+        bool continueOnSuccess;
+        bool continueOnFailure;
+        ValidationVisitor &validationVisitor;
+        ValidationResults * const results;
+        unsigned int * const numValidated;
+        bool * const validated;
+    };
+
+    /**
+     * @brief  Callback function that passes a visitor to a constraint.
+     *
+     * @param  constraint  Reference to constraint to be visited
+     * @param  visitor     Reference to visitor to be applied
+     *
+     * @return  true if the visitor returns successfully, false otherwise.
+     */
+    static bool validationCallback(const constraints::Constraint &constraint,
+                                   ValidationVisitor<AdapterType> &visitor)
+    {
+        return constraint.accept(visitor);
+    }
+
+    /// The JSON value being validated
+    const AdapterType target;
+
+    /// Vector of strings describing the current object context
+    const std::vector<std::string> context;
+
+    /// Optional pointer to a ValidationResults object to be populated
+    ValidationResults *results;
+
+    /// Option to use strict type comparison
+    const bool strictTypes;
+
+};
+
+}  // namespace valijson
+
+#endif
diff --git a/examples/validator/valijson/include/valijson/validator.hpp b/examples/validator/valijson/include/valijson/validator.hpp
new file mode 100644
index 0000000..4e4a586
--- /dev/null
+++ b/examples/validator/valijson/include/valijson/validator.hpp
@@ -0,0 +1,78 @@
+#pragma once
+#ifndef __VALIJSON_VALIDATOR_HPP
+#define __VALIJSON_VALIDATOR_HPP
+
+#include <valijson/schema.hpp>
+#include <valijson/validation_visitor.hpp>
+
+namespace valijson {
+
+class Schema;
+class ValidationResults;
+
+/**
+ * @brief  Class that provides validation functionality.
+ */
+class Validator
+{
+public:
+    enum TypeCheckingMode
+    {
+        kStrongTypes,
+        kWeakTypes
+    };
+
+    /**
+     * @brief  Construct a Validator that uses strong type checking by default
+     */
+    Validator()
+      : strictTypes(true) { }
+
+    /**
+     * @brief  Construct a Validator using a specific type checking mode
+     *
+     * @param  typeCheckingMode  choice of strong or weak type checking
+     */
+    Validator(TypeCheckingMode typeCheckingMode)
+      : strictTypes(typeCheckingMode == kStrongTypes) { }
+
+    /**
+     * @brief  Validate a JSON document and optionally return the results.
+     *
+     * When a ValidationResults object is provided via the \c results parameter,
+     * validation will be performed against each constraint defined by the
+     * schema, even if validation fails for some or all constraints.
+     *
+     * If a pointer to a ValidationResults instance is not provided, validation
+     * will only continue for as long as the constraints are validated
+     * successfully.
+     *
+     * @param  schema   The schema to validate against
+     * @param  target   A rapidjson::Value to be validated
+     *
+     * @param  results  An optional pointer to a ValidationResults instance that
+     *                  will be used to report validation errors
+     *
+     * @returns  true if validation succeeds, false otherwise
+     */
+    template<typename AdapterType>
+    bool validate(const Subschema &schema, const AdapterType &target,
+            ValidationResults *results)
+    {
+        // Construct a ValidationVisitor to perform validation at the root level
+        ValidationVisitor<AdapterType> v(target,
+                std::vector<std::string>(1, "<root>"), strictTypes, results);
+
+        return v.validateSchema(schema);
+    }
+
+private:
+
+    /// Flag indicating that strict type comparisons should be used
+    const bool strictTypes;
+
+};
+
+}  // namespace valijson
+
+#endif