From c33dbda379e0b44c11a39a577b8c81e4a0e1f0fb Mon Sep 17 00:00:00 2001
From: V S Tharunika <1vstharu279@gmail.com>
Date: Sun, 27 Dec 2020 13:50:13 +0530
Subject: [PATCH] installed 'joi'

---
 node_modules/@hapi/hoek/LICENSE.md            |   12 +
 node_modules/@hapi/hoek/README.md             |   19 +
 .../@hapi/hoek/lib/applyToDefaults.js         |   95 +
 node_modules/@hapi/hoek/lib/assert.js         |   21 +
 node_modules/@hapi/hoek/lib/bench.js          |   29 +
 node_modules/@hapi/hoek/lib/block.js          |   12 +
 node_modules/@hapi/hoek/lib/clone.js          |  176 ++
 node_modules/@hapi/hoek/lib/contain.js        |  307 +++
 node_modules/@hapi/hoek/lib/deepEqual.js      |  317 +++
 node_modules/@hapi/hoek/lib/error.js          |   26 +
 .../@hapi/hoek/lib/escapeHeaderAttribute.js   |   16 +
 node_modules/@hapi/hoek/lib/escapeHtml.js     |   87 +
 node_modules/@hapi/hoek/lib/escapeJson.js     |   41 +
 node_modules/@hapi/hoek/lib/escapeRegex.js    |   11 +
 node_modules/@hapi/hoek/lib/flatten.js        |   20 +
 node_modules/@hapi/hoek/lib/ignore.js         |    6 +
 node_modules/@hapi/hoek/lib/index.d.ts        |  471 ++++
 node_modules/@hapi/hoek/lib/index.js          |   29 +
 node_modules/@hapi/hoek/lib/intersect.js      |   41 +
 node_modules/@hapi/hoek/lib/isPromise.js      |    9 +
 node_modules/@hapi/hoek/lib/merge.js          |   78 +
 node_modules/@hapi/hoek/lib/once.js           |   23 +
 node_modules/@hapi/hoek/lib/reach.js          |   76 +
 node_modules/@hapi/hoek/lib/reachTemplate.js  |   16 +
 node_modules/@hapi/hoek/lib/stringify.js      |   14 +
 node_modules/@hapi/hoek/lib/types.js          |   55 +
 node_modules/@hapi/hoek/lib/utils.js          |    9 +
 node_modules/@hapi/hoek/lib/wait.js           |   13 +
 node_modules/@hapi/hoek/package.json          |   59 +
 node_modules/@hapi/topo/LICENSE.md            |   10 +
 node_modules/@hapi/topo/README.md             |   17 +
 node_modules/@hapi/topo/lib/index.d.ts        |   50 +
 node_modules/@hapi/topo/lib/index.js          |  215 ++
 node_modules/@hapi/topo/package.json          |   62 +
 node_modules/@sideway/address/LICENSE.md      |    9 +
 node_modules/@sideway/address/README.md       |   14 +
 node_modules/@sideway/address/lib/decode.js   |  120 +
 node_modules/@sideway/address/lib/domain.js   |  113 +
 node_modules/@sideway/address/lib/email.js    |  170 ++
 node_modules/@sideway/address/lib/errors.js   |   29 +
 node_modules/@sideway/address/lib/index.d.ts  |  255 ++
 node_modules/@sideway/address/lib/index.js    |   97 +
 node_modules/@sideway/address/lib/ip.js       |   63 +
 node_modules/@sideway/address/lib/tlds.js     | 1542 ++++++++++++
 node_modules/@sideway/address/lib/uri.js      |  207 ++
 node_modules/@sideway/address/package.json    |   63 +
 node_modules/@sideway/formula/LICENSE.md      |    9 +
 node_modules/@sideway/formula/README.md       |   18 +
 node_modules/@sideway/formula/lib/index.d.ts  |   52 +
 node_modules/@sideway/formula/lib/index.js    |  456 ++++
 node_modules/@sideway/formula/package.json    |   61 +
 node_modules/@sideway/pinpoint/LICENSE.md     |   10 +
 node_modules/@sideway/pinpoint/README.md      |   14 +
 node_modules/@sideway/pinpoint/lib/index.d.ts |   24 +
 node_modules/@sideway/pinpoint/lib/index.js   |   21 +
 node_modules/@sideway/pinpoint/package.json   |   58 +
 node_modules/joi/LICENSE.md                   |   10 +
 node_modules/joi/README.md                    |   15 +
 node_modules/joi/dist/joi-browser.min.js      |    1 +
 node_modules/joi/lib/annotate.js              |  175 ++
 node_modules/joi/lib/base.js                  | 1068 ++++++++
 node_modules/joi/lib/cache.js                 |  143 ++
 node_modules/joi/lib/common.js                |  216 ++
 node_modules/joi/lib/compile.js               |  283 +++
 node_modules/joi/lib/errors.js                |  262 ++
 node_modules/joi/lib/extend.js                |  312 +++
 node_modules/joi/lib/index.d.ts               | 2206 +++++++++++++++++
 node_modules/joi/lib/index.js                 |  283 +++
 node_modules/joi/lib/manifest.js              |  476 ++++
 node_modules/joi/lib/messages.js              |  178 ++
 node_modules/joi/lib/modify.js                |  267 ++
 node_modules/joi/lib/ref.js                   |  414 ++++
 node_modules/joi/lib/schemas.js               |  301 +++
 node_modules/joi/lib/state.js                 |  152 ++
 node_modules/joi/lib/template.js              |  427 ++++
 node_modules/joi/lib/trace.js                 |  346 +++
 node_modules/joi/lib/types/alternatives.js    |  329 +++
 node_modules/joi/lib/types/any.js             |  174 ++
 node_modules/joi/lib/types/array.js           |  775 ++++++
 node_modules/joi/lib/types/binary.js          |   98 +
 node_modules/joi/lib/types/boolean.js         |  150 ++
 node_modules/joi/lib/types/date.js            |  233 ++
 node_modules/joi/lib/types/function.js        |   93 +
 node_modules/joi/lib/types/keys.js            | 1043 ++++++++
 node_modules/joi/lib/types/link.js            |  168 ++
 node_modules/joi/lib/types/number.js          |  335 +++
 node_modules/joi/lib/types/object.js          |   22 +
 node_modules/joi/lib/types/string.js          |  820 ++++++
 node_modules/joi/lib/types/symbol.js          |  102 +
 node_modules/joi/lib/validator.js             |  650 +++++
 node_modules/joi/lib/values.js                |  263 ++
 node_modules/joi/package.json                 |   70 +
 package-lock.json                             |   49 +
 93 files changed, 18756 insertions(+)
 create mode 100644 node_modules/@hapi/hoek/LICENSE.md
 create mode 100644 node_modules/@hapi/hoek/README.md
 create mode 100644 node_modules/@hapi/hoek/lib/applyToDefaults.js
 create mode 100644 node_modules/@hapi/hoek/lib/assert.js
 create mode 100644 node_modules/@hapi/hoek/lib/bench.js
 create mode 100644 node_modules/@hapi/hoek/lib/block.js
 create mode 100644 node_modules/@hapi/hoek/lib/clone.js
 create mode 100644 node_modules/@hapi/hoek/lib/contain.js
 create mode 100644 node_modules/@hapi/hoek/lib/deepEqual.js
 create mode 100644 node_modules/@hapi/hoek/lib/error.js
 create mode 100644 node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js
 create mode 100644 node_modules/@hapi/hoek/lib/escapeHtml.js
 create mode 100644 node_modules/@hapi/hoek/lib/escapeJson.js
 create mode 100644 node_modules/@hapi/hoek/lib/escapeRegex.js
 create mode 100644 node_modules/@hapi/hoek/lib/flatten.js
 create mode 100644 node_modules/@hapi/hoek/lib/ignore.js
 create mode 100644 node_modules/@hapi/hoek/lib/index.d.ts
 create mode 100644 node_modules/@hapi/hoek/lib/index.js
 create mode 100644 node_modules/@hapi/hoek/lib/intersect.js
 create mode 100644 node_modules/@hapi/hoek/lib/isPromise.js
 create mode 100644 node_modules/@hapi/hoek/lib/merge.js
 create mode 100644 node_modules/@hapi/hoek/lib/once.js
 create mode 100644 node_modules/@hapi/hoek/lib/reach.js
 create mode 100644 node_modules/@hapi/hoek/lib/reachTemplate.js
 create mode 100644 node_modules/@hapi/hoek/lib/stringify.js
 create mode 100644 node_modules/@hapi/hoek/lib/types.js
 create mode 100644 node_modules/@hapi/hoek/lib/utils.js
 create mode 100644 node_modules/@hapi/hoek/lib/wait.js
 create mode 100644 node_modules/@hapi/hoek/package.json
 create mode 100644 node_modules/@hapi/topo/LICENSE.md
 create mode 100644 node_modules/@hapi/topo/README.md
 create mode 100644 node_modules/@hapi/topo/lib/index.d.ts
 create mode 100644 node_modules/@hapi/topo/lib/index.js
 create mode 100644 node_modules/@hapi/topo/package.json
 create mode 100644 node_modules/@sideway/address/LICENSE.md
 create mode 100644 node_modules/@sideway/address/README.md
 create mode 100644 node_modules/@sideway/address/lib/decode.js
 create mode 100644 node_modules/@sideway/address/lib/domain.js
 create mode 100644 node_modules/@sideway/address/lib/email.js
 create mode 100644 node_modules/@sideway/address/lib/errors.js
 create mode 100644 node_modules/@sideway/address/lib/index.d.ts
 create mode 100644 node_modules/@sideway/address/lib/index.js
 create mode 100644 node_modules/@sideway/address/lib/ip.js
 create mode 100644 node_modules/@sideway/address/lib/tlds.js
 create mode 100644 node_modules/@sideway/address/lib/uri.js
 create mode 100644 node_modules/@sideway/address/package.json
 create mode 100644 node_modules/@sideway/formula/LICENSE.md
 create mode 100644 node_modules/@sideway/formula/README.md
 create mode 100644 node_modules/@sideway/formula/lib/index.d.ts
 create mode 100644 node_modules/@sideway/formula/lib/index.js
 create mode 100644 node_modules/@sideway/formula/package.json
 create mode 100644 node_modules/@sideway/pinpoint/LICENSE.md
 create mode 100644 node_modules/@sideway/pinpoint/README.md
 create mode 100644 node_modules/@sideway/pinpoint/lib/index.d.ts
 create mode 100644 node_modules/@sideway/pinpoint/lib/index.js
 create mode 100644 node_modules/@sideway/pinpoint/package.json
 create mode 100644 node_modules/joi/LICENSE.md
 create mode 100644 node_modules/joi/README.md
 create mode 100644 node_modules/joi/dist/joi-browser.min.js
 create mode 100644 node_modules/joi/lib/annotate.js
 create mode 100644 node_modules/joi/lib/base.js
 create mode 100644 node_modules/joi/lib/cache.js
 create mode 100644 node_modules/joi/lib/common.js
 create mode 100644 node_modules/joi/lib/compile.js
 create mode 100644 node_modules/joi/lib/errors.js
 create mode 100644 node_modules/joi/lib/extend.js
 create mode 100644 node_modules/joi/lib/index.d.ts
 create mode 100644 node_modules/joi/lib/index.js
 create mode 100644 node_modules/joi/lib/manifest.js
 create mode 100644 node_modules/joi/lib/messages.js
 create mode 100644 node_modules/joi/lib/modify.js
 create mode 100644 node_modules/joi/lib/ref.js
 create mode 100644 node_modules/joi/lib/schemas.js
 create mode 100644 node_modules/joi/lib/state.js
 create mode 100644 node_modules/joi/lib/template.js
 create mode 100644 node_modules/joi/lib/trace.js
 create mode 100644 node_modules/joi/lib/types/alternatives.js
 create mode 100644 node_modules/joi/lib/types/any.js
 create mode 100644 node_modules/joi/lib/types/array.js
 create mode 100644 node_modules/joi/lib/types/binary.js
 create mode 100644 node_modules/joi/lib/types/boolean.js
 create mode 100644 node_modules/joi/lib/types/date.js
 create mode 100644 node_modules/joi/lib/types/function.js
 create mode 100644 node_modules/joi/lib/types/keys.js
 create mode 100644 node_modules/joi/lib/types/link.js
 create mode 100644 node_modules/joi/lib/types/number.js
 create mode 100644 node_modules/joi/lib/types/object.js
 create mode 100644 node_modules/joi/lib/types/string.js
 create mode 100644 node_modules/joi/lib/types/symbol.js
 create mode 100644 node_modules/joi/lib/validator.js
 create mode 100644 node_modules/joi/lib/values.js
 create mode 100644 node_modules/joi/package.json
 create mode 100644 package-lock.json

diff --git a/node_modules/@hapi/hoek/LICENSE.md b/node_modules/@hapi/hoek/LICENSE.md
new file mode 100644
index 00000000..0c95a4c7
--- /dev/null
+++ b/node_modules/@hapi/hoek/LICENSE.md
@@ -0,0 +1,12 @@
+Copyright (c) 2011-2020, Sideway Inc, and project contributors  
+Copyright (c) 2011-2014, Walmart  
+Copyright (c) 2011, Yahoo 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:
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+* 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.
+* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 HOLDERS AND 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 OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/@hapi/hoek/README.md b/node_modules/@hapi/hoek/README.md
new file mode 100644
index 00000000..8771dbfd
--- /dev/null
+++ b/node_modules/@hapi/hoek/README.md
@@ -0,0 +1,19 @@
+<a href="https://hapi.dev"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
+
+# @hapi/hoek
+
+#### Utility methods for the hapi ecosystem.
+
+**hoek** is part of the **hapi** ecosystem and was designed to work seamlessly with the [hapi web framework](https://hapi.dev) and its other components (but works great on its own or with other frameworks). If you are using a different web framework and find this module useful, check out [hapi](https://hapi.dev) – they work even better together.
+
+This module is not intended to solve every problem for everyone, but rather as a central place to store hapi-specific methods. If you're looking for a general purpose utility module, check out [lodash](https://github.com/lodash/lodash).
+
+### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
+
+## Useful resources
+
+- [Documentation and API](https://hapi.dev/family/hoek/)
+- [Version status](https://hapi.dev/resources/status/#hoek) (builds, dependencies, node versions, licenses, eol)
+- [Changelog](https://hapi.dev/family/hoek/changelog/)
+- [Project policies](https://hapi.dev/policies/)
+- [Free and commercial support options](https://hapi.dev/support/)
diff --git a/node_modules/@hapi/hoek/lib/applyToDefaults.js b/node_modules/@hapi/hoek/lib/applyToDefaults.js
new file mode 100644
index 00000000..54d96e66
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/applyToDefaults.js
@@ -0,0 +1,95 @@
+'use strict';
+
+const Assert = require('./assert');
+const Clone = require('./clone');
+const Merge = require('./merge');
+const Reach = require('./reach');
+
+
+const internals = {};
+
+
+module.exports = function (defaults, source, options = {}) {
+
+    Assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
+    Assert(!source || source === true || typeof source === 'object', 'Invalid source value: must be true, falsy or an object');
+    Assert(typeof options === 'object', 'Invalid options: must be an object');
+
+    if (!source) {                                                  // If no source, return null
+        return null;
+    }
+
+    if (options.shallow) {
+        return internals.applyToDefaultsWithShallow(defaults, source, options);
+    }
+
+    const copy = Clone(defaults);
+
+    if (source === true) {                                          // If source is set to true, use defaults
+        return copy;
+    }
+
+    const nullOverride = options.nullOverride !== undefined ? options.nullOverride : false;
+    return Merge(copy, source, { nullOverride, mergeArrays: false });
+};
+
+
+internals.applyToDefaultsWithShallow = function (defaults, source, options) {
+
+    const keys = options.shallow;
+    Assert(Array.isArray(keys), 'Invalid keys');
+
+    const seen = new Map();
+    const merge = source === true ? null : new Set();
+
+    for (let key of keys) {
+        key = Array.isArray(key) ? key : key.split('.');            // Pre-split optimization
+
+        const ref = Reach(defaults, key);
+        if (ref &&
+            typeof ref === 'object') {
+
+            seen.set(ref, merge && Reach(source, key) || ref);
+        }
+        else if (merge) {
+            merge.add(key);
+        }
+    }
+
+    const copy = Clone(defaults, {}, seen);
+
+    if (!merge) {
+        return copy;
+    }
+
+    for (const key of merge) {
+        internals.reachCopy(copy, source, key);
+    }
+
+    return Merge(copy, source, { mergeArrays: false, nullOverride: false });
+};
+
+
+internals.reachCopy = function (dst, src, path) {
+
+    for (const segment of path) {
+        if (!(segment in src)) {
+            return;
+        }
+
+        src = src[segment];
+    }
+
+    const value = src;
+    let ref = dst;
+    for (let i = 0; i < path.length - 1; ++i) {
+        const segment = path[i];
+        if (typeof ref[segment] !== 'object') {
+            ref[segment] = {};
+        }
+
+        ref = ref[segment];
+    }
+
+    ref[path[path.length - 1]] = value;
+};
diff --git a/node_modules/@hapi/hoek/lib/assert.js b/node_modules/@hapi/hoek/lib/assert.js
new file mode 100644
index 00000000..6a11e933
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/assert.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const AssertError = require('./error');
+
+const internals = {};
+
+
+module.exports = function (condition, ...args) {
+
+    if (condition) {
+        return;
+    }
+
+    if (args.length === 1 &&
+        args[0] instanceof Error) {
+
+        throw args[0];
+    }
+
+    throw new AssertError(args);
+};
diff --git a/node_modules/@hapi/hoek/lib/bench.js b/node_modules/@hapi/hoek/lib/bench.js
new file mode 100644
index 00000000..26ee1962
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/bench.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = internals.Bench = class {
+
+    constructor() {
+
+        this.ts = 0;
+        this.reset();
+    }
+
+    reset() {
+
+        this.ts = internals.Bench.now();
+    }
+
+    elapsed() {
+
+        return internals.Bench.now() - this.ts;
+    }
+
+    static now() {
+
+        const ts = process.hrtime();
+        return (ts[0] * 1e3) + (ts[1] / 1e6);
+    }
+};
diff --git a/node_modules/@hapi/hoek/lib/block.js b/node_modules/@hapi/hoek/lib/block.js
new file mode 100644
index 00000000..73fb9a53
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/block.js
@@ -0,0 +1,12 @@
+'use strict';
+
+const Ignore = require('./ignore');
+
+
+const internals = {};
+
+
+module.exports = function () {
+
+    return new Promise(Ignore);
+};
diff --git a/node_modules/@hapi/hoek/lib/clone.js b/node_modules/@hapi/hoek/lib/clone.js
new file mode 100644
index 00000000..e64defb8
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/clone.js
@@ -0,0 +1,176 @@
+'use strict';
+
+const Reach = require('./reach');
+const Types = require('./types');
+const Utils = require('./utils');
+
+
+const internals = {
+    needsProtoHack: new Set([Types.set, Types.map, Types.weakSet, Types.weakMap])
+};
+
+
+module.exports = internals.clone = function (obj, options = {}, _seen = null) {
+
+    if (typeof obj !== 'object' ||
+        obj === null) {
+
+        return obj;
+    }
+
+    let clone = internals.clone;
+    let seen = _seen;
+
+    if (options.shallow) {
+        if (options.shallow !== true) {
+            return internals.cloneWithShallow(obj, options);
+        }
+
+        clone = (value) => value;
+    }
+    else if (seen) {
+        const lookup = seen.get(obj);
+        if (lookup) {
+            return lookup;
+        }
+    }
+    else {
+        seen = new Map();
+    }
+
+    // Built-in object types
+
+    const baseProto = Types.getInternalProto(obj);
+    if (baseProto === Types.buffer) {
+        return Buffer && Buffer.from(obj);              // $lab:coverage:ignore$
+    }
+
+    if (baseProto === Types.date) {
+        return new Date(obj.getTime());
+    }
+
+    if (baseProto === Types.regex) {
+        return new RegExp(obj);
+    }
+
+    // Generic objects
+
+    const newObj = internals.base(obj, baseProto, options);
+    if (newObj === obj) {
+        return obj;
+    }
+
+    if (seen) {
+        seen.set(obj, newObj);                              // Set seen, since obj could recurse
+    }
+
+    if (baseProto === Types.set) {
+        for (const value of obj) {
+            newObj.add(clone(value, options, seen));
+        }
+    }
+    else if (baseProto === Types.map) {
+        for (const [key, value] of obj) {
+            newObj.set(key, clone(value, options, seen));
+        }
+    }
+
+    const keys = Utils.keys(obj, options);
+    for (const key of keys) {
+        if (key === '__proto__') {
+            continue;
+        }
+
+        if (baseProto === Types.array &&
+            key === 'length') {
+
+            newObj.length = obj.length;
+            continue;
+        }
+
+        const descriptor = Object.getOwnPropertyDescriptor(obj, key);
+        if (descriptor) {
+            if (descriptor.get ||
+                descriptor.set) {
+
+                Object.defineProperty(newObj, key, descriptor);
+            }
+            else if (descriptor.enumerable) {
+                newObj[key] = clone(obj[key], options, seen);
+            }
+            else {
+                Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone(obj[key], options, seen) });
+            }
+        }
+        else {
+            Object.defineProperty(newObj, key, {
+                enumerable: true,
+                writable: true,
+                configurable: true,
+                value: clone(obj[key], options, seen)
+            });
+        }
+    }
+
+    return newObj;
+};
+
+
+internals.cloneWithShallow = function (source, options) {
+
+    const keys = options.shallow;
+    options = Object.assign({}, options);
+    options.shallow = false;
+
+    const seen = new Map();
+
+    for (const key of keys) {
+        const ref = Reach(source, key);
+        if (typeof ref === 'object' ||
+            typeof ref === 'function') {
+
+            seen.set(ref, ref);
+        }
+    }
+
+    return internals.clone(source, options, seen);
+};
+
+
+internals.base = function (obj, baseProto, options) {
+
+    if (options.prototype === false) {                  // Defaults to true
+        if (internals.needsProtoHack.has(baseProto)) {
+            return new baseProto.constructor();
+        }
+
+        return baseProto === Types.array ? [] : {};
+    }
+
+    const proto = Object.getPrototypeOf(obj);
+    if (proto &&
+        proto.isImmutable) {
+
+        return obj;
+    }
+
+    if (baseProto === Types.array) {
+        const newObj = [];
+        if (proto !== baseProto) {
+            Object.setPrototypeOf(newObj, proto);
+        }
+
+        return newObj;
+    }
+
+    if (internals.needsProtoHack.has(baseProto)) {
+        const newObj = new proto.constructor();
+        if (proto !== baseProto) {
+            Object.setPrototypeOf(newObj, proto);
+        }
+
+        return newObj;
+    }
+
+    return Object.create(proto);
+};
diff --git a/node_modules/@hapi/hoek/lib/contain.js b/node_modules/@hapi/hoek/lib/contain.js
new file mode 100644
index 00000000..162ea3e8
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/contain.js
@@ -0,0 +1,307 @@
+'use strict';
+
+const Assert = require('./assert');
+const DeepEqual = require('./deepEqual');
+const EscapeRegex = require('./escapeRegex');
+const Utils = require('./utils');
+
+
+const internals = {};
+
+
+module.exports = function (ref, values, options = {}) {        // options: { deep, once, only, part, symbols }
+
+    /*
+        string -> string(s)
+        array -> item(s)
+        object -> key(s)
+        object -> object (key:value)
+    */
+
+    if (typeof values !== 'object') {
+        values = [values];
+    }
+
+    Assert(!Array.isArray(values) || values.length, 'Values array cannot be empty');
+
+    // String
+
+    if (typeof ref === 'string') {
+        return internals.string(ref, values, options);
+    }
+
+    // Array
+
+    if (Array.isArray(ref)) {
+        return internals.array(ref, values, options);
+    }
+
+    // Object
+
+    Assert(typeof ref === 'object', 'Reference must be string or an object');
+    return internals.object(ref, values, options);
+};
+
+
+internals.array = function (ref, values, options) {
+
+    if (!Array.isArray(values)) {
+        values = [values];
+    }
+
+    if (!ref.length) {
+        return false;
+    }
+
+    if (options.only &&
+        options.once &&
+        ref.length !== values.length) {
+
+        return false;
+    }
+
+    let compare;
+
+    // Map values
+
+    const map = new Map();
+    for (const value of values) {
+        if (!options.deep ||
+            !value ||
+            typeof value !== 'object') {
+
+            const existing = map.get(value);
+            if (existing) {
+                ++existing.allowed;
+            }
+            else {
+                map.set(value, { allowed: 1, hits: 0 });
+            }
+        }
+        else {
+            compare = compare || internals.compare(options);
+
+            let found = false;
+            for (const [key, existing] of map.entries()) {
+                if (compare(key, value)) {
+                    ++existing.allowed;
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found) {
+                map.set(value, { allowed: 1, hits: 0 });
+            }
+        }
+    }
+
+    // Lookup values
+
+    let hits = 0;
+    for (const item of ref) {
+        let match;
+        if (!options.deep ||
+            !item ||
+            typeof item !== 'object') {
+
+            match = map.get(item);
+        }
+        else {
+            compare = compare || internals.compare(options);
+
+            for (const [key, existing] of map.entries()) {
+                if (compare(key, item)) {
+                    match = existing;
+                    break;
+                }
+            }
+        }
+
+        if (match) {
+            ++match.hits;
+            ++hits;
+
+            if (options.once &&
+                match.hits > match.allowed) {
+
+                return false;
+            }
+        }
+    }
+
+    // Validate results
+
+    if (options.only &&
+        hits !== ref.length) {
+
+        return false;
+    }
+
+    for (const match of map.values()) {
+        if (match.hits === match.allowed) {
+            continue;
+        }
+
+        if (match.hits < match.allowed &&
+            !options.part) {
+
+            return false;
+        }
+    }
+
+    return !!hits;
+};
+
+
+internals.object = function (ref, values, options) {
+
+    Assert(options.once === undefined, 'Cannot use option once with object');
+
+    const keys = Utils.keys(ref, options);
+    if (!keys.length) {
+        return false;
+    }
+
+    // Keys list
+
+    if (Array.isArray(values)) {
+        return internals.array(keys, values, options);
+    }
+
+    // Key value pairs
+
+    const symbols = Object.getOwnPropertySymbols(values).filter((sym) => values.propertyIsEnumerable(sym));
+    const targets = [...Object.keys(values), ...symbols];
+
+    const compare = internals.compare(options);
+    const set = new Set(targets);
+
+    for (const key of keys) {
+        if (!set.has(key)) {
+            if (options.only) {
+                return false;
+            }
+
+            continue;
+        }
+
+        if (!compare(values[key], ref[key])) {
+            return false;
+        }
+
+        set.delete(key);
+    }
+
+    if (set.size) {
+        return options.part ? set.size < targets.length : false;
+    }
+
+    return true;
+};
+
+
+internals.string = function (ref, values, options) {
+
+    // Empty string
+
+    if (ref === '') {
+        return values.length === 1 && values[0] === '' ||               // '' contains ''
+            !options.once && !values.some((v) => v !== '');             // '' contains multiple '' if !once
+    }
+
+    // Map values
+
+    const map = new Map();
+    const patterns = [];
+
+    for (const value of values) {
+        Assert(typeof value === 'string', 'Cannot compare string reference to non-string value');
+
+        if (value) {
+            const existing = map.get(value);
+            if (existing) {
+                ++existing.allowed;
+            }
+            else {
+                map.set(value, { allowed: 1, hits: 0 });
+                patterns.push(EscapeRegex(value));
+            }
+        }
+        else if (options.once ||
+            options.only) {
+
+            return false;
+        }
+    }
+
+    if (!patterns.length) {                     // Non-empty string contains unlimited empty string
+        return true;
+    }
+
+    // Match patterns
+
+    const regex = new RegExp(`(${patterns.join('|')})`, 'g');
+    const leftovers = ref.replace(regex, ($0, $1) => {
+
+        ++map.get($1).hits;
+        return '';                              // Remove from string
+    });
+
+    // Validate results
+
+    if (options.only &&
+        leftovers) {
+
+        return false;
+    }
+
+    let any = false;
+    for (const match of map.values()) {
+        if (match.hits) {
+            any = true;
+        }
+
+        if (match.hits === match.allowed) {
+            continue;
+        }
+
+        if (match.hits < match.allowed &&
+            !options.part) {
+
+            return false;
+        }
+
+        // match.hits > match.allowed
+
+        if (options.once) {
+            return false;
+        }
+    }
+
+    return !!any;
+};
+
+
+internals.compare = function (options) {
+
+    if (!options.deep) {
+        return internals.shallow;
+    }
+
+    const hasOnly = options.only !== undefined;
+    const hasPart = options.part !== undefined;
+
+    const flags = {
+        prototype: hasOnly ? options.only : hasPart ? !options.part : false,
+        part: hasOnly ? !options.only : hasPart ? options.part : false
+    };
+
+    return (a, b) => DeepEqual(a, b, flags);
+};
+
+
+internals.shallow = function (a, b) {
+
+    return a === b;
+};
diff --git a/node_modules/@hapi/hoek/lib/deepEqual.js b/node_modules/@hapi/hoek/lib/deepEqual.js
new file mode 100644
index 00000000..a82647be
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/deepEqual.js
@@ -0,0 +1,317 @@
+'use strict';
+
+const Types = require('./types');
+
+
+const internals = {
+    mismatched: null
+};
+
+
+module.exports = function (obj, ref, options) {
+
+    options = Object.assign({ prototype: true }, options);
+
+    return !!internals.isDeepEqual(obj, ref, options, []);
+};
+
+
+internals.isDeepEqual = function (obj, ref, options, seen) {
+
+    if (obj === ref) {                                                      // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql
+        return obj !== 0 || 1 / obj === 1 / ref;
+    }
+
+    const type = typeof obj;
+
+    if (type !== typeof ref) {
+        return false;
+    }
+
+    if (obj === null ||
+        ref === null) {
+
+        return false;
+    }
+
+    if (type === 'function') {
+        if (!options.deepFunction ||
+            obj.toString() !== ref.toString()) {
+
+            return false;
+        }
+
+        // Continue as object
+    }
+    else if (type !== 'object') {
+        return obj !== obj && ref !== ref;                                  // NaN
+    }
+
+    const instanceType = internals.getSharedType(obj, ref, !!options.prototype);
+    switch (instanceType) {
+        case Types.buffer:
+            return Buffer && Buffer.prototype.equals.call(obj, ref);        // $lab:coverage:ignore$
+        case Types.promise:
+            return obj === ref;
+        case Types.regex:
+            return obj.toString() === ref.toString();
+        case internals.mismatched:
+            return false;
+    }
+
+    for (let i = seen.length - 1; i >= 0; --i) {
+        if (seen[i].isSame(obj, ref)) {
+            return true;                                                    // If previous comparison failed, it would have stopped execution
+        }
+    }
+
+    seen.push(new internals.SeenEntry(obj, ref));
+
+    try {
+        return !!internals.isDeepEqualObj(instanceType, obj, ref, options, seen);
+    }
+    finally {
+        seen.pop();
+    }
+};
+
+
+internals.getSharedType = function (obj, ref, checkPrototype) {
+
+    if (checkPrototype) {
+        if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {
+            return internals.mismatched;
+        }
+
+        return Types.getInternalProto(obj);
+    }
+
+    const type = Types.getInternalProto(obj);
+    if (type !== Types.getInternalProto(ref)) {
+        return internals.mismatched;
+    }
+
+    return type;
+};
+
+
+internals.valueOf = function (obj) {
+
+    const objValueOf = obj.valueOf;
+    if (objValueOf === undefined) {
+        return obj;
+    }
+
+    try {
+        return objValueOf.call(obj);
+    }
+    catch (err) {
+        return err;
+    }
+};
+
+
+internals.hasOwnEnumerableProperty = function (obj, key) {
+
+    return Object.prototype.propertyIsEnumerable.call(obj, key);
+};
+
+
+internals.isSetSimpleEqual = function (obj, ref) {
+
+    for (const entry of Set.prototype.values.call(obj)) {
+        if (!Set.prototype.has.call(ref, entry)) {
+            return false;
+        }
+    }
+
+    return true;
+};
+
+
+internals.isDeepEqualObj = function (instanceType, obj, ref, options, seen) {
+
+    const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals;
+    const { keys, getOwnPropertySymbols } = Object;
+
+    if (instanceType === Types.array) {
+        if (options.part) {
+
+            // Check if any index match any other index
+
+            for (const objValue of obj) {
+                for (const refValue of ref) {
+                    if (isDeepEqual(objValue, refValue, options, seen)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        else {
+            if (obj.length !== ref.length) {
+                return false;
+            }
+
+            for (let i = 0; i < obj.length; ++i) {
+                if (!isDeepEqual(obj[i], ref[i], options, seen)) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+    else if (instanceType === Types.set) {
+        if (obj.size !== ref.size) {
+            return false;
+        }
+
+        if (!internals.isSetSimpleEqual(obj, ref)) {
+
+            // Check for deep equality
+
+            const ref2 = new Set(Set.prototype.values.call(ref));
+            for (const objEntry of Set.prototype.values.call(obj)) {
+                if (ref2.delete(objEntry)) {
+                    continue;
+                }
+
+                let found = false;
+                for (const refEntry of ref2) {
+                    if (isDeepEqual(objEntry, refEntry, options, seen)) {
+                        ref2.delete(refEntry);
+                        found = true;
+                        break;
+                    }
+                }
+
+                if (!found) {
+                    return false;
+                }
+            }
+        }
+    }
+    else if (instanceType === Types.map) {
+        if (obj.size !== ref.size) {
+            return false;
+        }
+
+        for (const [key, value] of Map.prototype.entries.call(obj)) {
+            if (value === undefined && !Map.prototype.has.call(ref, key)) {
+                return false;
+            }
+
+            if (!isDeepEqual(value, Map.prototype.get.call(ref, key), options, seen)) {
+                return false;
+            }
+        }
+    }
+    else if (instanceType === Types.error) {
+
+        // Always check name and message
+
+        if (obj.name !== ref.name ||
+            obj.message !== ref.message) {
+
+            return false;
+        }
+    }
+
+    // Check .valueOf()
+
+    const valueOfObj = valueOf(obj);
+    const valueOfRef = valueOf(ref);
+    if ((obj !== valueOfObj || ref !== valueOfRef) &&
+        !isDeepEqual(valueOfObj, valueOfRef, options, seen)) {
+
+        return false;
+    }
+
+    // Check properties
+
+    const objKeys = keys(obj);
+    if (!options.part &&
+        objKeys.length !== keys(ref).length &&
+        !options.skip) {
+
+        return false;
+    }
+
+    let skipped = 0;
+    for (const key of objKeys) {
+        if (options.skip &&
+            options.skip.includes(key)) {
+
+            if (ref[key] === undefined) {
+                ++skipped;
+            }
+
+            continue;
+        }
+
+        if (!hasOwnEnumerableProperty(ref, key)) {
+            return false;
+        }
+
+        if (!isDeepEqual(obj[key], ref[key], options, seen)) {
+            return false;
+        }
+    }
+
+    if (!options.part &&
+        objKeys.length - skipped !== keys(ref).length) {
+
+        return false;
+    }
+
+    // Check symbols
+
+    if (options.symbols !== false) {                                // Defaults to true
+        const objSymbols = getOwnPropertySymbols(obj);
+        const refSymbols = new Set(getOwnPropertySymbols(ref));
+
+        for (const key of objSymbols) {
+            if (!options.skip ||
+                !options.skip.includes(key)) {
+
+                if (hasOwnEnumerableProperty(obj, key)) {
+                    if (!hasOwnEnumerableProperty(ref, key)) {
+                        return false;
+                    }
+
+                    if (!isDeepEqual(obj[key], ref[key], options, seen)) {
+                        return false;
+                    }
+                }
+                else if (hasOwnEnumerableProperty(ref, key)) {
+                    return false;
+                }
+            }
+
+            refSymbols.delete(key);
+        }
+
+        for (const key of refSymbols) {
+            if (hasOwnEnumerableProperty(ref, key)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+};
+
+
+internals.SeenEntry = class {
+
+    constructor(obj, ref) {
+
+        this.obj = obj;
+        this.ref = ref;
+    }
+
+    isSame(obj, ref) {
+
+        return this.obj === obj && this.ref === ref;
+    }
+};
diff --git a/node_modules/@hapi/hoek/lib/error.js b/node_modules/@hapi/hoek/lib/error.js
new file mode 100644
index 00000000..9fc4f5df
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/error.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const Stringify = require('./stringify');
+
+
+const internals = {};
+
+
+module.exports = class extends Error {
+
+    constructor(args) {
+
+        const msgs = args
+            .filter((arg) => arg !== '')
+            .map((arg) => {
+
+                return typeof arg === 'string' ? arg : arg instanceof Error ? arg.message : Stringify(arg);
+            });
+
+        super(msgs.join(' ') || 'Unknown error');
+
+        if (typeof Error.captureStackTrace === 'function') {            // $lab:coverage:ignore$
+            Error.captureStackTrace(this, exports.assert);
+        }
+    }
+};
diff --git a/node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js b/node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js
new file mode 100644
index 00000000..a0a4deea
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const Assert = require('./assert');
+
+
+const internals = {};
+
+
+module.exports = function (attribute) {
+
+    // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
+
+    Assert(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/.test(attribute), 'Bad attribute value (' + attribute + ')');
+
+    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');                             // Escape quotes and slash
+};
diff --git a/node_modules/@hapi/hoek/lib/escapeHtml.js b/node_modules/@hapi/hoek/lib/escapeHtml.js
new file mode 100644
index 00000000..ddef2b61
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/escapeHtml.js
@@ -0,0 +1,87 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (input) {
+
+    if (!input) {
+        return '';
+    }
+
+    let escaped = '';
+
+    for (let i = 0; i < input.length; ++i) {
+
+        const charCode = input.charCodeAt(i);
+
+        if (internals.isSafe(charCode)) {
+            escaped += input[i];
+        }
+        else {
+            escaped += internals.escapeHtmlChar(charCode);
+        }
+    }
+
+    return escaped;
+};
+
+
+internals.escapeHtmlChar = function (charCode) {
+
+    const namedEscape = internals.namedHtml[charCode];
+    if (typeof namedEscape !== 'undefined') {
+        return namedEscape;
+    }
+
+    if (charCode >= 256) {
+        return '&#' + charCode + ';';
+    }
+
+    const hexValue = charCode.toString(16).padStart(2, '0');
+    return `&#x${hexValue};`;
+};
+
+
+internals.isSafe = function (charCode) {
+
+    return (typeof internals.safeCharCodes[charCode] !== 'undefined');
+};
+
+
+internals.namedHtml = {
+    '38': '&amp;',
+    '60': '&lt;',
+    '62': '&gt;',
+    '34': '&quot;',
+    '160': '&nbsp;',
+    '162': '&cent;',
+    '163': '&pound;',
+    '164': '&curren;',
+    '169': '&copy;',
+    '174': '&reg;'
+};
+
+
+internals.safeCharCodes = (function () {
+
+    const safe = {};
+
+    for (let i = 32; i < 123; ++i) {
+
+        if ((i >= 97) ||                    // a-z
+            (i >= 65 && i <= 90) ||         // A-Z
+            (i >= 48 && i <= 57) ||         // 0-9
+            i === 32 ||                     // space
+            i === 46 ||                     // .
+            i === 44 ||                     // ,
+            i === 45 ||                     // -
+            i === 58 ||                     // :
+            i === 95) {                     // _
+
+            safe[i] = null;
+        }
+    }
+
+    return safe;
+}());
diff --git a/node_modules/@hapi/hoek/lib/escapeJson.js b/node_modules/@hapi/hoek/lib/escapeJson.js
new file mode 100644
index 00000000..e6e94b38
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/escapeJson.js
@@ -0,0 +1,41 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (input) {
+
+    if (!input) {
+        return '';
+    }
+
+    const lessThan = 0x3C;
+    const greaterThan = 0x3E;
+    const andSymbol = 0x26;
+    const lineSeperator = 0x2028;
+
+    // replace method
+    let charCode;
+    return input.replace(/[<>&\u2028\u2029]/g, (match) => {
+
+        charCode = match.charCodeAt(0);
+
+        if (charCode === lessThan) {
+            return '\\u003c';
+        }
+
+        if (charCode === greaterThan) {
+            return '\\u003e';
+        }
+
+        if (charCode === andSymbol) {
+            return '\\u0026';
+        }
+
+        if (charCode === lineSeperator) {
+            return '\\u2028';
+        }
+
+        return '\\u2029';
+    });
+};
diff --git a/node_modules/@hapi/hoek/lib/escapeRegex.js b/node_modules/@hapi/hoek/lib/escapeRegex.js
new file mode 100644
index 00000000..3272497e
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/escapeRegex.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (string) {
+
+    // Escape ^$.*+-?=!:|\/()[]{},
+
+    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
+};
diff --git a/node_modules/@hapi/hoek/lib/flatten.js b/node_modules/@hapi/hoek/lib/flatten.js
new file mode 100644
index 00000000..726e2314
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/flatten.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = internals.flatten = function (array, target) {
+
+    const result = target || [];
+
+    for (let i = 0; i < array.length; ++i) {
+        if (Array.isArray(array[i])) {
+            internals.flatten(array[i], result);
+        }
+        else {
+            result.push(array[i]);
+        }
+    }
+
+    return result;
+};
diff --git a/node_modules/@hapi/hoek/lib/ignore.js b/node_modules/@hapi/hoek/lib/ignore.js
new file mode 100644
index 00000000..21ad1443
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/ignore.js
@@ -0,0 +1,6 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function () { };
diff --git a/node_modules/@hapi/hoek/lib/index.d.ts b/node_modules/@hapi/hoek/lib/index.d.ts
new file mode 100644
index 00000000..e9bcdc28
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/index.d.ts
@@ -0,0 +1,471 @@
+/// <reference types="node" />
+
+
+/**
+ * Performs a deep comparison of the two values including support for circular dependencies, prototype, and enumerable properties.
+ *
+ * @param obj - The value being compared.
+ * @param ref - The reference value used for comparison.
+ * 
+ * @return true when the two values are equal, otherwise false.
+ */
+export function deepEqual(obj: any, ref: any, options?: deepEqual.Options): boolean;
+
+export namespace deepEqual {
+
+    interface Options {
+
+        /**
+         * Compare functions with difference references by comparing their internal code and properties.
+         *
+         * @default false
+         */
+        readonly deepFunction?: boolean;
+
+        /**
+         * Allow partial match.
+         *
+         * @default false
+         */
+        readonly part?: boolean;
+
+        /**
+         * Compare the objects' prototypes.
+         *
+         * @default true
+         */
+        readonly prototype?: boolean;
+
+        /**
+         * List of object keys to ignore different values of.
+         *
+         * @default null
+         */
+        readonly skip?: (string | symbol)[];
+
+        /**
+         * Compare symbol properties.
+         *
+         * @default true
+         */
+        readonly symbols?: boolean;
+    }
+}
+
+
+/**
+ * Clone any value, object, or array.
+ *
+ * @param obj - The value being cloned.
+ * @param options - Optional settings.
+ *
+ * @returns A deep clone of `obj`.
+ */
+export function clone<T>(obj: T, options?: clone.Options): T;
+
+export namespace clone {
+
+    interface Options {
+
+        /**
+         * Clone the object's prototype.
+         *
+         * @default true
+         */
+        readonly prototype?: boolean;
+
+        /**
+         * Include symbol properties.
+         *
+         * @default true
+         */
+        readonly symbols?: boolean;
+
+        /**
+         * Shallow clone the specified keys.
+         *
+         * @default undefined
+         */
+        readonly shallow?: string[] | string[][] | boolean;
+    }
+}
+
+
+/**
+ * Merge all the properties of source into target.
+ *
+ * @param target - The object being modified.
+ * @param source - The object used to copy properties from.
+ * @param options - Optional settings.
+ *
+ * @returns The `target` object.
+ */
+export function merge<T1 extends object, T2 extends object>(target: T1, source: T2, options?: merge.Options): T1 & T2;
+
+export namespace merge {
+
+    interface Options {
+
+        /**
+         * When true, null value from `source` overrides existing value in `target`.
+         *
+         * @default true
+         */
+        readonly nullOverride?: boolean;
+
+        /**
+         * When true, array value from `source` is merged with the existing value in `target`.
+         *
+         * @default false
+         */
+        readonly mergeArrays?: boolean;
+
+        /**
+         * Compare symbol properties.
+         *
+         * @default true
+         */
+        readonly symbols?: boolean;
+    }
+}
+
+
+/**
+ * Apply source to a copy of the defaults.
+ *
+ * @param defaults - An object with the default values to use of `options` does not contain the same keys.
+ * @param source - The source used to override the `defaults`.
+ * @param options - Optional settings.
+ *
+ * @returns A copy of `defaults` with `source` keys overriding any conflicts.
+ */
+export function applyToDefaults<T extends object>(defaults: Partial<T>, source: Partial<T> | boolean | null, options?: applyToDefaults.Options): Partial<T>;
+
+export namespace applyToDefaults {
+
+    interface Options {
+
+        /**
+         * When true, null value from `source` overrides existing value in `target`.
+         *
+         * @default true
+         */
+        readonly nullOverride?: boolean;
+
+        /**
+         * Shallow clone the specified keys.
+         *
+         * @default undefined
+         */
+        readonly shallow?: string[] | string[][];
+    }
+}
+
+
+/**
+ * Find the common unique items in two arrays.
+ *
+ * @param array1 - The first array to compare.
+ * @param array2 - The second array to compare.
+ * @param options - Optional settings.
+ *
+ * @return - An array of the common items. If `justFirst` is true, returns the first common item.
+ */
+export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, options?: intersect.Options): Array<T1 | T2>;
+export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, options?: intersect.Options): T1 | T2;
+
+export namespace intersect {
+
+    type Array<T> = ArrayLike<T> | Set<T> | null;
+
+    interface Options {
+
+        /**
+         * When true, return the first overlapping value.
+         *
+         * @default false
+         */
+        readonly first?: boolean;
+    }
+}
+
+
+/**
+ * Checks if the reference value contains the provided values.
+ *
+ * @param ref - The reference string, array, or object.
+ * @param values - A single or array of values to find within `ref`. If `ref` is an object, `values` can be a key name, an array of key names, or an object with key-value pairs to compare.
+ *
+ * @return true if the value contains the provided values, otherwise false.
+ */
+export function contain(ref: string, values: string | string[], options?: contain.Options): boolean;
+export function contain(ref: any[], values: any, options?: contain.Options): boolean;
+export function contain(ref: object, values: string | string[] | object, options?: Omit<contain.Options, 'once'>): boolean;
+
+export namespace contain {
+
+    interface Options {
+
+        /**
+         * Perform a deep comparison.
+         *
+         * @default false
+         */
+        readonly deep?: boolean;
+
+        /**
+         * Allow only one occurrence of each value.
+         *
+         * @default false
+         */
+        readonly once?: boolean;
+
+        /**
+         * Allow only values explicitly listed.
+         *
+         * @default false
+         */
+        readonly only?: boolean;
+
+        /**
+         * Allow partial match.
+         *
+         * @default false
+         */
+        readonly part?: boolean;
+
+        /**
+         * Include symbol properties.
+         *
+         * @default true
+         */
+        readonly symbols?: boolean;
+    }
+}
+
+
+/**
+ * Flatten an array with sub arrays
+ *
+ * @param array - an array of items or other arrays to flatten.
+ * @param target - if provided, an array to shallow copy the flattened `array` items to
+ *
+ * @return a flat array of the provided values (appended to `target` is provided).
+ */
+export function flatten<T>(array: ArrayLike<T | ReadonlyArray<T>>, target?: ArrayLike<T | ReadonlyArray<T>>): T[];
+
+
+/**
+ * Convert an object key chain string to reference.
+ *
+ * @param obj - the object from which to look up the value.
+ * @param chain - the string path of the requested value. The chain string is split into key names using `options.separator`, or an array containing each individual key name. A chain including negative numbers will work like a negative index on an array.
+ *
+ * @return The value referenced by the chain if found, otherwise undefined. If chain is null, undefined, or false, the object itself will be returned.
+ */
+export function reach(obj: object | null, chain: string | (string | number)[] | false | null | undefined, options?: reach.Options): any;
+
+export namespace reach {
+
+    interface Options {
+
+        /**
+         * String to split chain path on. Defaults to '.'.
+         *
+         * @default false
+         */
+        readonly separator?: string;
+
+        /**
+         * Value to return if the path or value is not present. No default value.
+         *
+         * @default false
+         */
+        readonly default?: any;
+
+        /**
+         * If true, will throw an error on missing member in the chain. Default to false.
+         *
+         * @default false
+         */
+        readonly strict?: boolean;
+
+        /**
+         * If true, allows traversing functions for properties. false will throw an error if a function is part of the chain.
+         *
+         * @default true
+         */
+        readonly functions?: boolean;
+
+        /**
+         * If true, allows traversing Set and Map objects for properties. false will return undefined regardless of the Set or Map passed.
+         *
+         * @default false
+         */
+        readonly iterables?: boolean;
+    }
+}
+
+
+/**
+ * Replace string parameters (using format "{path.to.key}") with their corresponding object key values using `Hoek.reach()`.
+ *
+ * @param obj - the object from which to look up the value.
+ * @param template - the string containing {} enclosed key paths to be replaced.
+ *
+ * @return The template string with the {} enclosed keys replaced with looked-up values.
+ */
+export function reachTemplate(obj: object | null, template: string, options?: reach.Options): string;
+
+
+/**
+ * Throw an error if condition is falsy.
+ *
+ * @param condition - If `condition` is not truthy, an exception is thrown.
+ * @param error - The error thrown if the condition fails.
+ *
+ * @return Does not return a value but throws if the `condition` is falsy.
+ */
+export function assert(condition: any, error: Error): void;
+
+
+/**
+ * Throw an error if condition is falsy.
+ *
+ * @param condition - If `condition` is not truthy, an exception is thrown.
+ * @param args - Any number of values, concatenated together (space separated) to create the error message.
+ *
+ * @return Does not return a value but throws if the `condition` is falsy.
+ */
+export function assert(condition: any, ...args: any): void;
+
+
+/**
+ * A benchmarking timer, using the internal node clock for maximum accuracy.
+ */
+export class Bench {
+
+    constructor();
+
+    /** The starting timestamp expressed in the number of milliseconds since the epoch. */
+    ts: number;
+
+    /** The time in milliseconds since the object was created. */
+    elapsed(): number;
+
+    /** Reset the `ts` value to now. */
+    reset(): void;
+
+    /** The current time in milliseconds since the epoch. */
+    static now(): number;
+}
+
+
+/**
+ * Escape string for Regex construction by prefixing all reserved characters with a backslash.
+ *
+ * @param string - The string to be escaped.
+ *
+ * @return The escaped string.
+ */
+export function escapeRegex(string: string): string;
+
+
+/**
+ * Escape string for usage as an attribute value in HTTP headers.
+ *
+ * @param attribute - The string to be escaped.
+ *
+ * @return The escaped string. Will throw on invalid characters that are not supported to be escaped.
+ */
+export function escapeHeaderAttribute(attribute: string): string;
+
+
+/**
+ * Escape string for usage in HTML.
+ *
+ * @param string - The string to be escaped.
+ *
+ * @return The escaped string.
+ */
+export function escapeHtml(string: string): string;
+
+
+/**
+ * Escape string for usage in JSON.
+ *
+ * @param string - The string to be escaped.
+ *
+ * @return The escaped string.
+ */
+export function escapeJson(string: string): string;
+
+
+/**
+ * Wraps a function to ensure it can only execute once.
+ *
+ * @param method - The function to be wrapped.
+ *
+ * @return The wrapped function.
+ */
+export function once<T extends Function>(method: T): T;
+
+
+/**
+ * A reusable no-op function.
+ */
+export function ignore(...ignore: any): void;
+
+
+/**
+ * Converts a JavaScript value to a JavaScript Object Notation (JSON) string with protection against thrown errors.
+ *
+ * @param value A JavaScript value, usually an object or array, to be converted.
+ * @param replacer The JSON.stringify() `replacer` argument.
+ * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
+ *
+ * @return The JSON string. If the operation fails, an error string value is returned (no exception thrown).
+ */
+export function stringify(value: any, replacer?: any, space?: string | number): string;
+
+
+/**
+ * Returns a Promise that resolves after the requested timeout.
+ *
+ * @param timeout - The number of milliseconds to wait before resolving the Promise.
+ * @param returnValue - The value that the Promise will resolve to.
+ *
+ * @return A Promise that resolves with `returnValue`.
+ */
+export function wait<T>(timeout?: number, returnValue?: T): Promise<T>;
+
+
+/**
+ * Returns a Promise that never resolves.
+ */
+export function block(): Promise<void>;
+
+
+/**
+ * Determines if an object is a promise.
+ * 
+ * @param promise - the object tested.
+ * 
+ * @returns true if the object is a promise, otherwise false.
+ */
+export function isPromise(promise: any): boolean;
+
+
+export namespace ts {
+
+    /**
+     * Defines a type that can must be one of T or U but not both.
+     */
+    type XOR<T, U> = (T | U) extends object ? (internals.Without<T, U> & U) | (internals.Without<U, T> & T) : T | U;
+}
+
+
+declare namespace internals {
+
+    type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
+}
diff --git a/node_modules/@hapi/hoek/lib/index.js b/node_modules/@hapi/hoek/lib/index.js
new file mode 100644
index 00000000..ea062698
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/index.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = {
+    applyToDefaults: require('./applyToDefaults'),
+    assert: require('./assert'),
+    Bench: require('./bench'),
+    block: require('./block'),
+    clone: require('./clone'),
+    contain: require('./contain'),
+    deepEqual: require('./deepEqual'),
+    Error: require('./error'),
+    escapeHeaderAttribute: require('./escapeHeaderAttribute'),
+    escapeHtml: require('./escapeHtml'),
+    escapeJson: require('./escapeJson'),
+    escapeRegex: require('./escapeRegex'),
+    flatten: require('./flatten'),
+    ignore: require('./ignore'),
+    intersect: require('./intersect'),
+    isPromise: require('./isPromise'),
+    merge: require('./merge'),
+    once: require('./once'),
+    reach: require('./reach'),
+    reachTemplate: require('./reachTemplate'),
+    stringify: require('./stringify'),
+    wait: require('./wait')
+};
diff --git a/node_modules/@hapi/hoek/lib/intersect.js b/node_modules/@hapi/hoek/lib/intersect.js
new file mode 100644
index 00000000..59e6aaf1
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/intersect.js
@@ -0,0 +1,41 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (array1, array2, options = {}) {
+
+    if (!array1 ||
+        !array2) {
+
+        return (options.first ? null : []);
+    }
+
+    const common = [];
+    const hash = (Array.isArray(array1) ? new Set(array1) : array1);
+    const found = new Set();
+    for (const value of array2) {
+        if (internals.has(hash, value) &&
+            !found.has(value)) {
+
+            if (options.first) {
+                return value;
+            }
+
+            common.push(value);
+            found.add(value);
+        }
+    }
+
+    return (options.first ? null : common);
+};
+
+
+internals.has = function (ref, key) {
+
+    if (typeof ref.has === 'function') {
+        return ref.has(key);
+    }
+
+    return ref[key] !== undefined;
+};
diff --git a/node_modules/@hapi/hoek/lib/isPromise.js b/node_modules/@hapi/hoek/lib/isPromise.js
new file mode 100644
index 00000000..40298040
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/isPromise.js
@@ -0,0 +1,9 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (promise) {
+
+    return !!promise && typeof promise.then === 'function';
+};
diff --git a/node_modules/@hapi/hoek/lib/merge.js b/node_modules/@hapi/hoek/lib/merge.js
new file mode 100644
index 00000000..47a1e1e9
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/merge.js
@@ -0,0 +1,78 @@
+'use strict';
+
+const Assert = require('./assert');
+const Clone = require('./clone');
+const Utils = require('./utils');
+
+
+const internals = {};
+
+
+module.exports = internals.merge = function (target, source, options) {
+
+    Assert(target && typeof target === 'object', 'Invalid target value: must be an object');
+    Assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
+
+    if (!source) {
+        return target;
+    }
+
+    options = Object.assign({ nullOverride: true, mergeArrays: true }, options);
+
+    if (Array.isArray(source)) {
+        Assert(Array.isArray(target), 'Cannot merge array onto an object');
+        if (!options.mergeArrays) {
+            target.length = 0;                                                          // Must not change target assignment
+        }
+
+        for (let i = 0; i < source.length; ++i) {
+            target.push(Clone(source[i], { symbols: options.symbols }));
+        }
+
+        return target;
+    }
+
+    const keys = Utils.keys(source, options);
+    for (let i = 0; i < keys.length; ++i) {
+        const key = keys[i];
+        if (key === '__proto__' ||
+            !Object.prototype.propertyIsEnumerable.call(source, key)) {
+
+            continue;
+        }
+
+        const value = source[key];
+        if (value &&
+            typeof value === 'object') {
+
+            if (target[key] === value) {
+                continue;                                           // Can occur for shallow merges
+            }
+
+            if (!target[key] ||
+                typeof target[key] !== 'object' ||
+                (Array.isArray(target[key]) !== Array.isArray(value)) ||
+                value instanceof Date ||
+                (Buffer && Buffer.isBuffer(value)) ||               // $lab:coverage:ignore$
+                value instanceof RegExp) {
+
+                target[key] = Clone(value, { symbols: options.symbols });
+            }
+            else {
+                internals.merge(target[key], value, options);
+            }
+        }
+        else {
+            if (value !== null &&
+                value !== undefined) {                              // Explicit to preserve empty strings
+
+                target[key] = value;
+            }
+            else if (options.nullOverride) {
+                target[key] = value;
+            }
+        }
+    }
+
+    return target;
+};
diff --git a/node_modules/@hapi/hoek/lib/once.js b/node_modules/@hapi/hoek/lib/once.js
new file mode 100644
index 00000000..de94ea0a
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/once.js
@@ -0,0 +1,23 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (method) {
+
+    if (method._hoekOnce) {
+        return method;
+    }
+
+    let once = false;
+    const wrapped = function (...args) {
+
+        if (!once) {
+            once = true;
+            method(...args);
+        }
+    };
+
+    wrapped._hoekOnce = true;
+    return wrapped;
+};
diff --git a/node_modules/@hapi/hoek/lib/reach.js b/node_modules/@hapi/hoek/lib/reach.js
new file mode 100644
index 00000000..3791b37b
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/reach.js
@@ -0,0 +1,76 @@
+'use strict';
+
+const Assert = require('./assert');
+
+
+const internals = {};
+
+
+module.exports = function (obj, chain, options) {
+
+    if (chain === false ||
+        chain === null ||
+        chain === undefined) {
+
+        return obj;
+    }
+
+    options = options || {};
+    if (typeof options === 'string') {
+        options = { separator: options };
+    }
+
+    const isChainArray = Array.isArray(chain);
+
+    Assert(!isChainArray || !options.separator, 'Separator option no valid for array-based chain');
+
+    const path = isChainArray ? chain : chain.split(options.separator || '.');
+    let ref = obj;
+    for (let i = 0; i < path.length; ++i) {
+        let key = path[i];
+        const type = options.iterables && internals.iterables(ref);
+
+        if (Array.isArray(ref) ||
+            type === 'set') {
+
+            const number = Number(key);
+            if (Number.isInteger(number)) {
+                key = number < 0 ? ref.length + number : number;
+            }
+        }
+
+        if (!ref ||
+            typeof ref === 'function' && options.functions === false ||         // Defaults to true
+            !type && ref[key] === undefined) {
+
+            Assert(!options.strict || i + 1 === path.length, 'Missing segment', key, 'in reach path ', chain);
+            Assert(typeof ref === 'object' || options.functions === true || typeof ref !== 'function', 'Invalid segment', key, 'in reach path ', chain);
+            ref = options.default;
+            break;
+        }
+
+        if (!type) {
+            ref = ref[key];
+        }
+        else if (type === 'set') {
+            ref = [...ref][key];
+        }
+        else {  // type === 'map'
+            ref = ref.get(key);
+        }
+    }
+
+    return ref;
+};
+
+
+internals.iterables = function (ref) {
+
+    if (ref instanceof Set) {
+        return 'set';
+    }
+
+    if (ref instanceof Map) {
+        return 'map';
+    }
+};
diff --git a/node_modules/@hapi/hoek/lib/reachTemplate.js b/node_modules/@hapi/hoek/lib/reachTemplate.js
new file mode 100644
index 00000000..e48ac406
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/reachTemplate.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const Reach = require('./reach');
+
+
+const internals = {};
+
+
+module.exports = function (obj, template, options) {
+
+    return template.replace(/{([^}]+)}/g, ($0, chain) => {
+
+        const value = Reach(obj, chain, options);
+        return (value === undefined || value === null ? '' : value);
+    });
+};
diff --git a/node_modules/@hapi/hoek/lib/stringify.js b/node_modules/@hapi/hoek/lib/stringify.js
new file mode 100644
index 00000000..88d0fc4e
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/stringify.js
@@ -0,0 +1,14 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (...args) {
+
+    try {
+        return JSON.stringify.apply(null, args);
+    }
+    catch (err) {
+        return '[Cannot display object: ' + err.message + ']';
+    }
+};
diff --git a/node_modules/@hapi/hoek/lib/types.js b/node_modules/@hapi/hoek/lib/types.js
new file mode 100644
index 00000000..c291b657
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/types.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const internals = {};
+
+
+exports = module.exports = {
+    array: Array.prototype,
+    buffer: Buffer && Buffer.prototype,             // $lab:coverage:ignore$
+    date: Date.prototype,
+    error: Error.prototype,
+    generic: Object.prototype,
+    map: Map.prototype,
+    promise: Promise.prototype,
+    regex: RegExp.prototype,
+    set: Set.prototype,
+    weakMap: WeakMap.prototype,
+    weakSet: WeakSet.prototype
+};
+
+
+internals.typeMap = new Map([
+    ['[object Error]', exports.error],
+    ['[object Map]', exports.map],
+    ['[object Promise]', exports.promise],
+    ['[object Set]', exports.set],
+    ['[object WeakMap]', exports.weakMap],
+    ['[object WeakSet]', exports.weakSet]
+]);
+
+
+exports.getInternalProto = function (obj) {
+
+    if (Array.isArray(obj)) {
+        return exports.array;
+    }
+
+    if (Buffer && obj instanceof Buffer) {          // $lab:coverage:ignore$
+        return exports.buffer;
+    }
+
+    if (obj instanceof Date) {
+        return exports.date;
+    }
+
+    if (obj instanceof RegExp) {
+        return exports.regex;
+    }
+
+    if (obj instanceof Error) {
+        return exports.error;
+    }
+
+    const objName = Object.prototype.toString.call(obj);
+    return internals.typeMap.get(objName) || exports.generic;
+};
diff --git a/node_modules/@hapi/hoek/lib/utils.js b/node_modules/@hapi/hoek/lib/utils.js
new file mode 100644
index 00000000..bab1e8c4
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/utils.js
@@ -0,0 +1,9 @@
+'use strict';
+
+const internals = {};
+
+
+exports.keys = function (obj, options = {}) {
+
+    return options.symbols !== false ? Reflect.ownKeys(obj) : Object.getOwnPropertyNames(obj);  // Defaults to true
+};
diff --git a/node_modules/@hapi/hoek/lib/wait.js b/node_modules/@hapi/hoek/lib/wait.js
new file mode 100644
index 00000000..f34585ef
--- /dev/null
+++ b/node_modules/@hapi/hoek/lib/wait.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const internals = {};
+
+
+module.exports = function (timeout, returnValue) {
+
+    if (typeof timeout !== 'number' && timeout !== undefined) {
+        throw new TypeError('Timeout must be a number');
+    }
+
+    return new Promise((resolve) => setTimeout(resolve, timeout, returnValue));
+};
diff --git a/node_modules/@hapi/hoek/package.json b/node_modules/@hapi/hoek/package.json
new file mode 100644
index 00000000..8b19b9ec
--- /dev/null
+++ b/node_modules/@hapi/hoek/package.json
@@ -0,0 +1,59 @@
+{
+  "_from": "@hapi/hoek@^9.0.0",
+  "_id": "@hapi/hoek@9.1.0",
+  "_inBundle": false,
+  "_integrity": "sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw==",
+  "_location": "/@hapi/hoek",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "@hapi/hoek@^9.0.0",
+    "name": "@hapi/hoek",
+    "escapedName": "@hapi%2fhoek",
+    "scope": "@hapi",
+    "rawSpec": "^9.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^9.0.0"
+  },
+  "_requiredBy": [
+    "/@hapi/topo",
+    "/@sideway/address",
+    "/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.1.0.tgz",
+  "_shasum": "6c9eafc78c1529248f8f4d92b0799a712b6052c6",
+  "_spec": "@hapi/hoek@^9.0.0",
+  "_where": "C:\\Users\\V S THARUNIKA\\Documents\\book-racker\\node_modules\\joi",
+  "bugs": {
+    "url": "https://github.com/hapijs/hoek/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "General purpose node utilities",
+  "devDependencies": {
+    "@hapi/code": "8.x.x",
+    "@hapi/lab": "^23.0.0"
+  },
+  "files": [
+    "lib"
+  ],
+  "homepage": "https://github.com/hapijs/hoek#readme",
+  "keywords": [
+    "utilities"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "@hapi/hoek",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hapijs/hoek.git"
+  },
+  "scripts": {
+    "test": "lab -a @hapi/code -t 100 -L -Y",
+    "test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
+  },
+  "types": "lib/index.d.ts",
+  "version": "9.1.0"
+}
diff --git a/node_modules/@hapi/topo/LICENSE.md b/node_modules/@hapi/topo/LICENSE.md
new file mode 100644
index 00000000..0d96bf8f
--- /dev/null
+++ b/node_modules/@hapi/topo/LICENSE.md
@@ -0,0 +1,10 @@
+Copyright (c) 2012-2020, Sideway Inc, and project contributors  
+Copyright (c) 2012-2014, Walmart.  
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+* 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.
+* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 HOLDERS AND 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 OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/@hapi/topo/README.md b/node_modules/@hapi/topo/README.md
new file mode 100644
index 00000000..118bacba
--- /dev/null
+++ b/node_modules/@hapi/topo/README.md
@@ -0,0 +1,17 @@
+<a href="https://hapi.dev"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
+
+# @hapi/topo
+
+#### Topological sorting with grouping support.
+
+**topo** is part of the **hapi** ecosystem and was designed to work seamlessly with the [hapi web framework](https://hapi.dev) and its other components (but works great on its own or with other frameworks). If you are using a different web framework and find this module useful, check out [hapi](https://hapi.dev) – they work even better together.
+
+### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
+
+## Useful resources
+
+- [Documentation and API](https://hapi.dev/family/topo/)
+- [Version status](https://hapi.dev/resources/status/#topo) (builds, dependencies, node versions, licenses, eol)
+- [Changelog](https://hapi.dev/family/topo/changelog/)
+- [Project policies](https://hapi.dev/policies/)
+- [Free and commercial support options](https://hapi.dev/support/)
diff --git a/node_modules/@hapi/topo/lib/index.d.ts b/node_modules/@hapi/topo/lib/index.d.ts
new file mode 100644
index 00000000..475c71ae
--- /dev/null
+++ b/node_modules/@hapi/topo/lib/index.d.ts
@@ -0,0 +1,50 @@
+export class Sorter<T> {
+
+    /**
+     * An array of the topologically sorted nodes. This list is renewed upon each call to topo.add().
+     */
+    nodes: T[];
+
+    /**
+     * Adds a node or list of nodes to be added and topologically sorted
+     * 
+     * @param nodes - A mixed value or array of mixed values to be added as nodes to the topologically sorted list.
+     * @param options - Optional sorting information about the nodes.
+     * 
+     * @returns Returns an array of the topologically sorted nodes.
+     */
+    add(nodes: T | T[], options?: Options): T[];
+
+    /**
+     * Merges another Sorter object into the current object.
+     * 
+     * @param others - The other object or array of objects to be merged into the current one.
+     * 
+     * @returns Returns an array of the topologically sorted nodes.
+     */
+    merge(others: Sorter<T> | Sorter<T>[]): T[];
+}
+
+
+export interface Options {
+
+    /**
+     * The sorting group the added items belong to
+     */
+    readonly group?: string;
+
+    /**
+     * The group or groups the added items must come before
+     */
+    readonly before?: string | string[];
+
+    /**
+     * The group or groups the added items must come after
+     */
+    readonly after?: string | string[];
+
+    /**
+     * A number used to sort items with equal before/after requirements
+     */
+    readonly sort?: number;
+}
diff --git a/node_modules/@hapi/topo/lib/index.js b/node_modules/@hapi/topo/lib/index.js
new file mode 100644
index 00000000..d2c684c5
--- /dev/null
+++ b/node_modules/@hapi/topo/lib/index.js
@@ -0,0 +1,215 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+
+const internals = {};
+
+
+exports.Sorter = class {
+
+    constructor() {
+
+        this._items = [];
+        this.nodes = [];
+    }
+
+    add(nodes, options) {
+
+        options = options || {};
+
+        // Validate rules
+
+        const before = [].concat(options.before || []);
+        const after = [].concat(options.after || []);
+        const group = options.group || '?';
+        const sort = options.sort || 0;                   // Used for merging only
+
+        Assert(!before.includes(group), `Item cannot come before itself: ${group}`);
+        Assert(!before.includes('?'), 'Item cannot come before unassociated items');
+        Assert(!after.includes(group), `Item cannot come after itself: ${group}`);
+        Assert(!after.includes('?'), 'Item cannot come after unassociated items');
+
+        if (!Array.isArray(nodes)) {
+            nodes = [nodes];
+        }
+
+        for (const node of nodes) {
+            const item = {
+                seq: this._items.length,
+                sort,
+                before,
+                after,
+                group,
+                node
+            };
+
+            this._items.push(item);
+        }
+
+        // Insert event
+
+        const valid = this._sort();
+        Assert(valid, 'item', group !== '?' ? `added into group ${group}` : '', 'created a dependencies error');
+
+        return this.nodes;
+    }
+
+    merge(others) {
+
+        if (!Array.isArray(others)) {
+            others = [others];
+        }
+
+        for (const other of others) {
+            if (other) {
+                for (const item of other._items) {
+                    this._items.push(Object.assign({}, item));      // Shallow cloned
+                }
+            }
+        }
+
+        // Sort items
+
+        this._items.sort(internals.mergeSort);
+        for (let i = 0; i < this._items.length; ++i) {
+            this._items[i].seq = i;
+        }
+
+        const valid = this._sort();
+        Assert(valid, 'merge created a dependencies error');
+
+        return this.nodes;
+    }
+
+    _sort() {
+
+        // Construct graph
+
+        const graph = {};
+        const graphAfters = Object.create(null);            // A prototype can bungle lookups w/ false positives
+        const groups = Object.create(null);
+
+        for (const item of this._items) {
+            const seq = item.seq;                           // Unique across all items
+            const group = item.group;
+
+            // Determine Groups
+
+            groups[group] = groups[group] || [];
+            groups[group].push(seq);
+
+            // Build intermediary graph using 'before'
+
+            graph[seq] = item.before;
+
+            // Build second intermediary graph with 'after'
+
+            for (const after of item.after) {
+                graphAfters[after] = graphAfters[after] || [];
+                graphAfters[after].push(seq);
+            }
+        }
+
+        // Expand intermediary graph
+
+        for (const node in graph) {
+            const expandedGroups = [];
+
+            for (const graphNodeItem in graph[node]) {
+                const group = graph[node][graphNodeItem];
+                groups[group] = groups[group] || [];
+                expandedGroups.push(...groups[group]);
+            }
+
+            graph[node] = expandedGroups;
+        }
+
+        // Merge intermediary graph using graphAfters into final graph
+
+        for (const group in graphAfters) {
+            if (groups[group]) {
+                for (const node of groups[group]) {
+                    graph[node].push(...graphAfters[group]);
+                }
+            }
+        }
+
+        // Compile ancestors
+
+        const ancestors = {};
+        for (const node in graph) {
+            const children = graph[node];
+            for (const child of children) {
+                ancestors[child] = ancestors[child] || [];
+                ancestors[child].push(node);
+            }
+        }
+
+        // Topo sort
+
+        const visited = {};
+        const sorted = [];
+
+        for (let i = 0; i < this._items.length; ++i) {          // Looping through item.seq values out of order
+            let next = i;
+
+            if (ancestors[i]) {
+                next = null;
+                for (let j = 0; j < this._items.length; ++j) {  // As above, these are item.seq values
+                    if (visited[j] === true) {
+                        continue;
+                    }
+
+                    if (!ancestors[j]) {
+                        ancestors[j] = [];
+                    }
+
+                    const shouldSeeCount = ancestors[j].length;
+                    let seenCount = 0;
+                    for (let k = 0; k < shouldSeeCount; ++k) {
+                        if (visited[ancestors[j][k]]) {
+                            ++seenCount;
+                        }
+                    }
+
+                    if (seenCount === shouldSeeCount) {
+                        next = j;
+                        break;
+                    }
+                }
+            }
+
+            if (next !== null) {
+                visited[next] = true;
+                sorted.push(next);
+            }
+        }
+
+        if (sorted.length !== this._items.length) {
+            return false;
+        }
+
+        const seqIndex = {};
+        for (const item of this._items) {
+            seqIndex[item.seq] = item;
+        }
+
+        this._items = [];
+        this.nodes = [];
+
+        for (const value of sorted) {
+            const sortedItem = seqIndex[value];
+            this.nodes.push(sortedItem.node);
+            this._items.push(sortedItem);
+        }
+
+        return true;
+    }
+};
+
+
+internals.mergeSort = (a, b) => {
+
+    return a.sort === b.sort ? 0 : (a.sort < b.sort ? -1 : 1);
+};
diff --git a/node_modules/@hapi/topo/package.json b/node_modules/@hapi/topo/package.json
new file mode 100644
index 00000000..7fc7b6b0
--- /dev/null
+++ b/node_modules/@hapi/topo/package.json
@@ -0,0 +1,62 @@
+{
+  "_from": "@hapi/topo@^5.0.0",
+  "_id": "@hapi/topo@5.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==",
+  "_location": "/@hapi/topo",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "@hapi/topo@^5.0.0",
+    "name": "@hapi/topo",
+    "escapedName": "@hapi%2ftopo",
+    "scope": "@hapi",
+    "rawSpec": "^5.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^5.0.0"
+  },
+  "_requiredBy": [
+    "/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz",
+  "_shasum": "c19af8577fa393a06e9c77b60995af959be721e7",
+  "_spec": "@hapi/topo@^5.0.0",
+  "_where": "C:\\Users\\V S THARUNIKA\\Documents\\book-racker\\node_modules\\joi",
+  "bugs": {
+    "url": "https://github.com/hapijs/topo/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "@hapi/hoek": "^9.0.0"
+  },
+  "deprecated": false,
+  "description": "Topological sorting with grouping support",
+  "devDependencies": {
+    "@hapi/code": "8.x.x",
+    "@hapi/lab": "22.x.x"
+  },
+  "files": [
+    "lib"
+  ],
+  "homepage": "https://github.com/hapijs/topo#readme",
+  "keywords": [
+    "topological",
+    "sort",
+    "toposort",
+    "topsort"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "@hapi/topo",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hapijs/topo.git"
+  },
+  "scripts": {
+    "test": "lab -a @hapi/code -t 100 -L -Y",
+    "test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
+  },
+  "types": "lib/index.d.ts",
+  "version": "5.0.0"
+}
diff --git a/node_modules/@sideway/address/LICENSE.md b/node_modules/@sideway/address/LICENSE.md
new file mode 100644
index 00000000..0c6e658d
--- /dev/null
+++ b/node_modules/@sideway/address/LICENSE.md
@@ -0,0 +1,9 @@
+Copyright (c) 2019-2020, Sideway, Inc. and Project contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * 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.
+ * The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 HOLDERS AND 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/node_modules/@sideway/address/README.md b/node_modules/@sideway/address/README.md
new file mode 100644
index 00000000..c26895fe
--- /dev/null
+++ b/node_modules/@sideway/address/README.md
@@ -0,0 +1,14 @@
+# @sideway/address
+
+#### Validate email address and domain.
+
+**address** is part of the **joi** ecosystem.
+
+### Visit the [joi.dev](https://joi.dev) Developer Portal for tutorials, documentation, and support
+
+## Useful resources
+
+- [Documentation and API](https://joi.dev/module/address/)
+- [Versions status](https://joi.dev/resources/status/#address)
+- [Changelog](https://joi.dev/module/address/changelog/)
+- [Project policies](https://joi.dev/policies/)
diff --git a/node_modules/@sideway/address/lib/decode.js b/node_modules/@sideway/address/lib/decode.js
new file mode 100644
index 00000000..06a12369
--- /dev/null
+++ b/node_modules/@sideway/address/lib/decode.js
@@ -0,0 +1,120 @@
+'use strict';
+
+// Adapted from:
+// Copyright (c) 2017-2019 Justin Ridgewell, MIT Licensed, https://github.com/jridgewell/safe-decode-string-component
+// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>, MIT Licensed, http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+
+
+const internals = {};
+
+
+exports.decode = function (string) {
+
+    let percentPos = string.indexOf('%');
+    if (percentPos === -1) {
+        return string;
+    }
+
+    let decoded = '';
+    let last = 0;
+    let codepoint = 0;
+    let startOfOctets = percentPos;
+    let state = internals.utf8.accept;
+
+    while (percentPos > -1 &&
+        percentPos < string.length) {
+
+        const high = internals.resolveHex(string[percentPos + 1], 4);
+        const low = internals.resolveHex(string[percentPos + 2], 0);
+        const byte = high | low;
+        const type = internals.utf8.data[byte];
+        state = internals.utf8.data[256 + state + type];
+        codepoint = (codepoint << 6) | (byte & internals.utf8.data[364 + type]);
+
+        if (state === internals.utf8.accept) {
+            decoded += string.slice(last, startOfOctets);
+            decoded += codepoint <= 0xFFFF
+                ? String.fromCharCode(codepoint)
+                : String.fromCharCode(0xD7C0 + (codepoint >> 10), 0xDC00 + (codepoint & 0x3FF));
+
+            codepoint = 0;
+            last = percentPos + 3;
+            percentPos = string.indexOf('%', last);
+            startOfOctets = percentPos;
+            continue;
+        }
+
+        if (state === internals.utf8.reject) {
+            return null;
+        }
+
+        percentPos += 3;
+
+        if (percentPos >= string.length ||
+            string[percentPos] !== '%') {
+
+            return null;
+        }
+    }
+
+    return decoded + string.slice(last);
+};
+
+
+internals.resolveHex = function (char, shift) {
+
+    const i = internals.hex[char];
+    return i === undefined ? 255 : i << shift;
+};
+
+
+internals.hex = {
+    '0': 0, '1': 1, '2': 2, '3': 3, '4': 4,
+    '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
+    'a': 10, 'A': 10, 'b': 11, 'B': 11, 'c': 12,
+    'C': 12, 'd': 13, 'D': 13, 'e': 14, 'E': 14,
+    'f': 15, 'F': 15
+};
+
+
+internals.utf8 = {
+    accept: 12,
+    reject: 0,
+    data: [
+
+        // Maps bytes to character to a transition
+
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+        6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 7,
+        10, 9, 9, 9, 11, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+
+        // Maps a state to a new state when adding a transition
+
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        12, 0, 0, 0, 0, 24, 36, 48, 60, 72, 84, 96,
+        0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+        // Maps the current transition to a mask that needs to apply to the byte
+
+        0x7F, 0x3F, 0x3F, 0x3F, 0x00, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07
+    ]
+};
diff --git a/node_modules/@sideway/address/lib/domain.js b/node_modules/@sideway/address/lib/domain.js
new file mode 100644
index 00000000..e96bf5ef
--- /dev/null
+++ b/node_modules/@sideway/address/lib/domain.js
@@ -0,0 +1,113 @@
+'use strict';
+
+const Url = require('url');
+
+const Errors = require('./errors');
+
+
+const internals = {
+    minDomainSegments: 2,
+    nonAsciiRx: /[^\x00-\x7f]/,
+    domainControlRx: /[\x00-\x20@\:\/]/,                                                // Control + space + separators
+    tldSegmentRx: /^[a-zA-Z](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,
+    domainSegmentRx: /^[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,
+    URL: Url.URL || URL                                                                 // $lab:coverage:ignore$
+};
+
+
+exports.analyze = function (domain, options = {}) {
+
+    if (typeof domain !== 'string') {
+        throw new Error('Invalid input: domain must be a string');
+    }
+
+    if (!domain) {
+        return Errors.code('DOMAIN_NON_EMPTY_STRING');
+    }
+
+    if (domain.length > 256) {
+        return Errors.code('DOMAIN_TOO_LONG');
+    }
+
+    const ascii = !internals.nonAsciiRx.test(domain);
+    if (!ascii) {
+        if (options.allowUnicode === false) {                                           // Defaults to true
+            return Errors.code('DOMAIN_INVALID_UNICODE_CHARS');
+        }
+
+        domain = domain.normalize('NFC');
+    }
+
+    if (internals.domainControlRx.test(domain)) {
+        return Errors.code('DOMAIN_INVALID_CHARS');
+    }
+
+    domain = internals.punycode(domain);
+
+    // https://tools.ietf.org/html/rfc1035 section 2.3.1
+
+    const minDomainSegments = options.minDomainSegments || internals.minDomainSegments;
+
+    const segments = domain.split('.');
+    if (segments.length < minDomainSegments) {
+        return Errors.code('DOMAIN_SEGMENTS_COUNT');
+    }
+
+    if (options.maxDomainSegments) {
+        if (segments.length > options.maxDomainSegments) {
+            return Errors.code('DOMAIN_SEGMENTS_COUNT_MAX');
+        }
+    }
+
+    const tlds = options.tlds;
+    if (tlds) {
+        const tld = segments[segments.length - 1].toLowerCase();
+        if (tlds.deny && tlds.deny.has(tld) ||
+            tlds.allow && !tlds.allow.has(tld)) {
+
+            return Errors.code('DOMAIN_FORBIDDEN_TLDS');
+        }
+    }
+
+    for (let i = 0; i < segments.length; ++i) {
+        const segment = segments[i];
+
+        if (!segment.length) {
+            return Errors.code('DOMAIN_EMPTY_SEGMENT');
+        }
+
+        if (segment.length > 63) {
+            return Errors.code('DOMAIN_LONG_SEGMENT');
+        }
+
+        if (i < segments.length - 1) {
+            if (!internals.domainSegmentRx.test(segment)) {
+                return Errors.code('DOMAIN_INVALID_CHARS');
+            }
+        }
+        else {
+            if (!internals.tldSegmentRx.test(segment)) {
+                return Errors.code('DOMAIN_INVALID_TLDS_CHARS');
+            }
+        }
+    }
+
+    return null;
+};
+
+
+exports.isValid = function (domain, options) {
+
+    return !exports.analyze(domain, options);
+};
+
+
+internals.punycode = function (domain) {
+
+    try {
+        return new internals.URL(`http://${domain}`).host;
+    }
+    catch (err) {
+        return domain;
+    }
+};
diff --git a/node_modules/@sideway/address/lib/email.js b/node_modules/@sideway/address/lib/email.js
new file mode 100644
index 00000000..8343ab7e
--- /dev/null
+++ b/node_modules/@sideway/address/lib/email.js
@@ -0,0 +1,170 @@
+'use strict';
+
+const Util = require('util');
+
+const Domain = require('./domain');
+const Errors = require('./errors');
+
+
+const internals = {
+    nonAsciiRx: /[^\x00-\x7f]/,
+    encoder: new (Util.TextEncoder || TextEncoder)()                                            // $lab:coverage:ignore$
+};
+
+
+exports.analyze = function (email, options) {
+
+    return internals.email(email, options);
+};
+
+
+exports.isValid = function (email, options) {
+
+    return !internals.email(email, options);
+};
+
+
+internals.email = function (email, options = {}) {
+
+    if (typeof email !== 'string') {
+        throw new Error('Invalid input: email must be a string');
+    }
+
+    if (!email) {
+        return Errors.code('EMPTY_STRING');
+    }
+
+    // Unicode
+
+    const ascii = !internals.nonAsciiRx.test(email);
+    if (!ascii) {
+        if (options.allowUnicode === false) {                                                   // Defaults to true
+            return Errors.code('FORBIDDEN_UNICODE');
+        }
+
+        email = email.normalize('NFC');
+    }
+
+    // Basic structure
+
+    const parts = email.split('@');
+    if (parts.length !== 2) {
+        return parts.length > 2 ? Errors.code('MULTIPLE_AT_CHAR') : Errors.code('MISSING_AT_CHAR');
+    }
+
+    const [local, domain] = parts;
+
+    if (!local) {
+        return Errors.code('EMPTY_LOCAL');
+    }
+
+    if (!options.ignoreLength) {
+        if (email.length > 254) {                                           // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3
+            return Errors.code('ADDRESS_TOO_LONG');
+        }
+
+        if (internals.encoder.encode(local).length > 64) {                  // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
+            return Errors.code('LOCAL_TOO_LONG');
+        }
+    }
+
+    // Validate parts
+
+    return internals.local(local, ascii) || Domain.analyze(domain, options);
+};
+
+
+internals.local = function (local, ascii) {
+
+    const segments = local.split('.');
+    for (const segment of segments) {
+        if (!segment.length) {
+            return Errors.code('EMPTY_LOCAL_SEGMENT');
+        }
+
+        if (ascii) {
+            if (!internals.atextRx.test(segment)) {
+                return Errors.code('INVALID_LOCAL_CHARS');
+            }
+
+            continue;
+        }
+
+        for (const char of segment) {
+            if (internals.atextRx.test(char)) {
+                continue;
+            }
+
+            const binary = internals.binary(char);
+            if (!internals.atomRx.test(binary)) {
+                return Errors.code('INVALID_LOCAL_CHARS');
+            }
+        }
+    }
+};
+
+
+internals.binary = function (char) {
+
+    return Array.from(internals.encoder.encode(char)).map((v) => String.fromCharCode(v)).join('');
+};
+
+
+/*
+    From RFC 5321:
+
+        Mailbox         =   Local-part "@" ( Domain / address-literal )
+
+        Local-part      =   Dot-string / Quoted-string
+        Dot-string      =   Atom *("."  Atom)
+        Atom            =   1*atext
+        atext           =   ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
+
+        Domain          =   sub-domain *("." sub-domain)
+        sub-domain      =   Let-dig [Ldh-str]
+        Let-dig         =   ALPHA / DIGIT
+        Ldh-str         =   *( ALPHA / DIGIT / "-" ) Let-dig
+
+        ALPHA           =   %x41-5A / %x61-7A        ; a-z, A-Z
+        DIGIT           =   %x30-39                  ; 0-9
+
+    From RFC 6531:
+
+        sub-domain      =/  U-label
+        atext           =/  UTF8-non-ascii
+
+        UTF8-non-ascii  =   UTF8-2 / UTF8-3 / UTF8-4
+
+        UTF8-2          =   %xC2-DF UTF8-tail
+        UTF8-3          =   %xE0 %xA0-BF UTF8-tail /
+                            %xE1-EC 2( UTF8-tail ) /
+                            %xED %x80-9F UTF8-tail /
+                            %xEE-EF 2( UTF8-tail )
+        UTF8-4          =   %xF0 %x90-BF 2( UTF8-tail ) /
+                            %xF1-F3 3( UTF8-tail ) /
+                            %xF4 %x80-8F 2( UTF8-tail )
+
+        UTF8-tail       =   %x80-BF
+
+    Note: The following are not supported:
+
+        RFC 5321: address-literal, Quoted-string
+        RFC 5322: obs-*, CFWS
+*/
+
+
+internals.atextRx = /^[\w!#\$%&'\*\+\-/=\?\^`\{\|\}~]+$/;               // _ included in \w
+
+
+internals.atomRx = new RegExp([
+
+    //  %xC2-DF UTF8-tail
+    '(?:[\\xc2-\\xdf][\\x80-\\xbf])',
+
+    //  %xE0 %xA0-BF UTF8-tail              %xE1-EC 2( UTF8-tail )            %xED %x80-9F UTF8-tail              %xEE-EF 2( UTF8-tail )
+    '(?:\\xe0[\\xa0-\\xbf][\\x80-\\xbf])|(?:[\\xe1-\\xec][\\x80-\\xbf]{2})|(?:\\xed[\\x80-\\x9f][\\x80-\\xbf])|(?:[\\xee-\\xef][\\x80-\\xbf]{2})',
+
+    //  %xF0 %x90-BF 2( UTF8-tail )            %xF1-F3 3( UTF8-tail )            %xF4 %x80-8F 2( UTF8-tail )
+    '(?:\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2})|(?:[\\xf1-\\xf3][\\x80-\\xbf]{3})|(?:\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})'
+
+].join('|'));
diff --git a/node_modules/@sideway/address/lib/errors.js b/node_modules/@sideway/address/lib/errors.js
new file mode 100644
index 00000000..001dd106
--- /dev/null
+++ b/node_modules/@sideway/address/lib/errors.js
@@ -0,0 +1,29 @@
+'use strict';
+
+exports.codes = {
+    EMPTY_STRING: 'Address must be a non-empty string',
+    FORBIDDEN_UNICODE: 'Address contains forbidden Unicode characters',
+    MULTIPLE_AT_CHAR: 'Address cannot contain more than one @ character',
+    MISSING_AT_CHAR: 'Address must contain one @ character',
+    EMPTY_LOCAL: 'Address local part cannot be empty',
+    ADDRESS_TOO_LONG: 'Address too long',
+    LOCAL_TOO_LONG: 'Address local part too long',
+    EMPTY_LOCAL_SEGMENT: 'Address local part contains empty dot-separated segment',
+    INVALID_LOCAL_CHARS: 'Address local part contains invalid character',
+    DOMAIN_NON_EMPTY_STRING: 'Domain must be a non-empty string',
+    DOMAIN_TOO_LONG: 'Domain too long',
+    DOMAIN_INVALID_UNICODE_CHARS: 'Domain contains forbidden Unicode characters',
+    DOMAIN_INVALID_CHARS: 'Domain contains invalid character',
+    DOMAIN_INVALID_TLDS_CHARS: 'Domain contains invalid tld character',
+    DOMAIN_SEGMENTS_COUNT: 'Domain lacks the minimum required number of segments',
+    DOMAIN_SEGMENTS_COUNT_MAX: 'Domain contains too many segments',
+    DOMAIN_FORBIDDEN_TLDS: 'Domain uses forbidden TLD',
+    DOMAIN_EMPTY_SEGMENT: 'Domain contains empty dot-separated segment',
+    DOMAIN_LONG_SEGMENT: 'Domain contains dot-separated segment that is too long'
+};
+
+
+exports.code = function (code) {
+
+    return { code, error: exports.codes[code] };
+};
diff --git a/node_modules/@sideway/address/lib/index.d.ts b/node_modules/@sideway/address/lib/index.d.ts
new file mode 100644
index 00000000..a533d737
--- /dev/null
+++ b/node_modules/@sideway/address/lib/index.d.ts
@@ -0,0 +1,255 @@
+/// <reference types="node" />
+
+import * as Hoek from '@hapi/hoek';
+
+
+export namespace domain {
+
+    /**
+     * Analyzes a string to verify it is a valid domain name.
+     * 
+     * @param domain - the domain name to validate.
+     * @param options - optional settings.
+     * 
+     * @return - undefined when valid, otherwise an object with single error key with a string message value.
+     */
+    function analyze(domain: string, options?: Options): Analysis | null;
+
+    /**
+     * Analyzes a string to verify it is a valid domain name.
+     * 
+     * @param domain - the domain name to validate.
+     * @param options - optional settings.
+     * 
+     * @return - true when valid, otherwise false.
+     */
+    function isValid(domain: string, options?: Options): boolean;
+
+    interface Options {
+
+        /**
+         * Determines whether Unicode characters are allowed.
+         * 
+         * @default true
+         */
+        readonly allowUnicode?: boolean;
+
+        /**
+         * The minimum number of domain segments (e.g. `x.y.z` has 3 segments) required.
+         * 
+         * @default 2
+         */
+        readonly minDomainSegments?: number;
+
+        /**
+         * Top-level-domain options
+         * 
+         * @default true
+         */
+        readonly tlds?: Tlds.Allow | Tlds.Deny | boolean;
+    }
+
+    namespace Tlds {
+
+        interface Allow {
+
+            readonly allow: Set<string> | true;
+        }
+
+        interface Deny {
+
+            readonly deny: Set<string>;
+        }
+    }
+}
+
+
+export namespace email {
+
+    /**
+     * Analyzes a string to verify it is a valid email address.
+     * 
+     * @param email - the email address to validate.
+     * @param options - optional settings.
+     * 
+     * @return - undefined when valid, otherwise an object with single error key with a string message value.
+     */
+    function analyze(email: string, options?: Options): Analysis | null;
+
+    /**
+     * Analyzes a string to verify it is a valid email address.
+     * 
+     * @param email - the email address to validate.
+     * @param options - optional settings.
+     * 
+     * @return - true when valid, otherwise false.
+     */
+    function isValid(email: string, options?: Options): boolean;
+
+    interface Options extends domain.Options {
+
+        /**
+         * Determines whether to ignore the standards maximum email length limit.
+         * 
+         * @default false
+         */
+        readonly ignoreLength?: boolean;
+    }
+}
+
+
+export interface Analysis {
+
+    /**
+     * The reason validation failed.
+     */
+    error: string;
+
+    /**
+     * The error code.
+     */
+    code: string;
+}
+
+
+export const errors: Record<string, string>;
+
+
+export namespace ip {
+
+    /**
+     * Generates a regular expression used to validate IP addresses.
+     * 
+     * @param options - optional settings.
+     * 
+     * @returns an object with the regular expression and meta data.
+     */
+    function regex(options?: Options): Expression;
+
+    interface Options {
+
+        /**
+         * The required CIDR mode.
+         * 
+         * @default 'optional'
+         */
+        readonly cidr?: Cidr;
+
+        /**
+         * The allowed versions.
+         * 
+         * @default ['ipv4', 'ipv6', 'ipvfuture']
+         */
+        readonly version?: Version | Version[];
+    }
+
+    type Cidr = 'optional' | 'required' | 'forbidden';
+    type Version = 'ipv4' | 'ipv6' | 'ipvfuture';
+
+    interface Expression {
+
+        /**
+         * The CIDR mode.
+         */
+        cidr: Cidr;
+
+        /**
+         * The raw regular expression string.
+         */
+        raw: string;
+
+        /**
+         * The regular expression.
+         */
+        regex: RegExp;
+
+        /**
+         * The array of versions allowed.
+         */
+        versions: Version[];
+    }
+}
+
+
+export namespace uri {
+
+    /**
+     * Faster version of decodeURIComponent() that does not throw.
+     * 
+     * @param string - the URL string to decode.
+     * 
+     * @returns the decoded string or null if invalid.
+     */
+    function decode(string: string): string | null;
+
+    /**
+     * Generates a regular expression used to validate URI addresses.
+     *
+     * @param options - optional settings.
+     *
+     * @returns an object with the regular expression and meta data.
+     */
+    function regex(options?: Options): Expression;
+
+    type Options = Hoek.ts.XOR<Options.Options, Options.Relative>;
+
+    namespace Options {
+
+        interface Query {
+
+            /**
+             * Allow the use of [] in query parameters.
+             * 
+             * @default false
+             */
+            readonly allowQuerySquareBrackets?: boolean;
+        }
+
+        interface Relative extends Query {
+
+            /**
+             * Requires the URI to be relative.
+             * 
+             * @default false
+             */
+            readonly relativeOnly?: boolean;
+        }
+
+        interface Options extends Query {
+
+            /**
+             * Allow relative URIs.
+             * 
+             * @default false
+             */
+            readonly allowRelative?: boolean;
+
+            /**
+             * Capture domain segment ($1).
+             * 
+             * @default false
+             */
+            readonly domain?: boolean;
+
+            /**
+             * The allowed URI schemes.
+             */
+            readonly scheme?: Scheme | Scheme[];
+        }
+
+        type Scheme = string | RegExp;
+    }
+
+    interface Expression {
+
+        /**
+         * The raw regular expression string.
+         */
+        raw: string;
+
+        /**
+         * The regular expression.
+         */
+        regex: RegExp;
+    }
+}
diff --git a/node_modules/@sideway/address/lib/index.js b/node_modules/@sideway/address/lib/index.js
new file mode 100644
index 00000000..b93a9c5c
--- /dev/null
+++ b/node_modules/@sideway/address/lib/index.js
@@ -0,0 +1,97 @@
+'use strict';
+
+const Decode = require('./decode');
+const Domain = require('./domain');
+const Email = require('./email');
+const Errors = require('./errors');
+const Ip = require('./ip');
+const Tlds = require('./tlds');
+const Uri = require('./uri');
+
+
+const internals = {
+    defaultTlds: { allow: Tlds, deny: null }
+};
+
+
+module.exports = {
+    errors: Errors.codes,
+
+    domain: {
+        analyze(domain, options) {
+
+            options = internals.options(options);
+            return Domain.analyze(domain, options);
+        },
+
+        isValid(domain, options) {
+
+            options = internals.options(options);
+            return Domain.isValid(domain, options);
+        }
+    },
+    email: {
+        analyze(email, options) {
+
+            options = internals.options(options);
+            return Email.analyze(email, options);
+        },
+
+        isValid(email, options) {
+
+            options = internals.options(options);
+            return Email.isValid(email, options);
+        }
+    },
+    ip: {
+        regex: Ip.regex
+    },
+    uri: {
+        decode: Decode.decode,
+        regex: Uri.regex
+    }
+};
+
+
+internals.options = function (options) {
+
+    if (!options) {
+        return { tlds: internals.defaultTlds };
+    }
+
+    if (options.tlds === false) {                // Defaults to true
+        return options;
+    }
+
+    if (!options.tlds ||
+        options.tlds === true) {
+
+        return Object.assign({}, options, { tlds: internals.defaultTlds });
+    }
+
+    if (typeof options.tlds !== 'object') {
+        throw new Error('Invalid options: tlds must be a boolean or an object');
+    }
+
+    if (options.tlds.deny) {
+        if (options.tlds.deny instanceof Set === false) {
+            throw new Error('Invalid options: tlds.deny must be a Set object');
+        }
+
+        if (options.tlds.allow) {
+            throw new Error('Invalid options: cannot specify both tlds.allow and tlds.deny lists');
+        }
+
+        return options;
+    }
+
+    if (options.tlds.allow === true) {
+        return Object.assign({}, options, { tlds: internals.defaultTlds });
+    }
+
+    if (options.tlds.allow instanceof Set === false) {
+        throw new Error('Invalid options: tlds.allow must be a Set object or true');
+    }
+
+    return options;
+};
diff --git a/node_modules/@sideway/address/lib/ip.js b/node_modules/@sideway/address/lib/ip.js
new file mode 100644
index 00000000..541b72cc
--- /dev/null
+++ b/node_modules/@sideway/address/lib/ip.js
@@ -0,0 +1,63 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Uri = require('./uri');
+
+
+const internals = {};
+
+
+exports.regex = function (options = {}) {
+
+    // CIDR
+
+    Assert(options.cidr === undefined || typeof options.cidr === 'string', 'options.cidr must be a string');
+    const cidr = options.cidr ? options.cidr.toLowerCase() : 'optional';
+    Assert(['required', 'optional', 'forbidden'].includes(cidr), 'options.cidr must be one of required, optional, forbidden');
+
+    // Versions
+
+    Assert(options.version === undefined || typeof options.version === 'string' || Array.isArray(options.version), 'options.version must be a string or an array of string');
+    let versions = options.version || ['ipv4', 'ipv6', 'ipvfuture'];
+    if (!Array.isArray(versions)) {
+        versions = [versions];
+    }
+
+    Assert(versions.length >= 1, 'options.version must have at least 1 version specified');
+
+    for (let i = 0; i < versions.length; ++i) {
+        Assert(typeof versions[i] === 'string', 'options.version must only contain strings');
+        versions[i] = versions[i].toLowerCase();
+        Assert(['ipv4', 'ipv6', 'ipvfuture'].includes(versions[i]), 'options.version contains unknown version ' + versions[i] + ' - must be one of ipv4, ipv6, ipvfuture');
+    }
+
+    versions = Array.from(new Set(versions));
+
+    // Regex
+
+    const parts = versions.map((version) => {
+
+        // Forbidden
+
+        if (cidr === 'forbidden') {
+            return Uri.ip[version];
+        }
+
+        // Required
+
+        const cidrpart = `\\/${version === 'ipv4' ? Uri.ip.v4Cidr : Uri.ip.v6Cidr}`;
+
+        if (cidr === 'required') {
+            return `${Uri.ip[version]}${cidrpart}`;
+        }
+
+        // Optional
+
+        return `${Uri.ip[version]}(?:${cidrpart})?`;
+    });
+
+    const raw = `(?:${parts.join('|')})`;
+    const regex = new RegExp(`^${raw}$`);
+    return { cidr, versions, regex, raw };
+};
diff --git a/node_modules/@sideway/address/lib/tlds.js b/node_modules/@sideway/address/lib/tlds.js
new file mode 100644
index 00000000..77a00e3d
--- /dev/null
+++ b/node_modules/@sideway/address/lib/tlds.js
@@ -0,0 +1,1542 @@
+'use strict';
+
+const internals = {};
+
+
+// http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+// # Version 2019091902, Last Updated Fri Sep 20 07: 07: 02 2019 UTC
+
+
+internals.tlds = [
+    'AAA',
+    'AARP',
+    'ABARTH',
+    'ABB',
+    'ABBOTT',
+    'ABBVIE',
+    'ABC',
+    'ABLE',
+    'ABOGADO',
+    'ABUDHABI',
+    'AC',
+    'ACADEMY',
+    'ACCENTURE',
+    'ACCOUNTANT',
+    'ACCOUNTANTS',
+    'ACO',
+    'ACTOR',
+    'AD',
+    'ADAC',
+    'ADS',
+    'ADULT',
+    'AE',
+    'AEG',
+    'AERO',
+    'AETNA',
+    'AF',
+    'AFAMILYCOMPANY',
+    'AFL',
+    'AFRICA',
+    'AG',
+    'AGAKHAN',
+    'AGENCY',
+    'AI',
+    'AIG',
+    'AIGO',
+    'AIRBUS',
+    'AIRFORCE',
+    'AIRTEL',
+    'AKDN',
+    'AL',
+    'ALFAROMEO',
+    'ALIBABA',
+    'ALIPAY',
+    'ALLFINANZ',
+    'ALLSTATE',
+    'ALLY',
+    'ALSACE',
+    'ALSTOM',
+    'AM',
+    'AMERICANEXPRESS',
+    'AMERICANFAMILY',
+    'AMEX',
+    'AMFAM',
+    'AMICA',
+    'AMSTERDAM',
+    'ANALYTICS',
+    'ANDROID',
+    'ANQUAN',
+    'ANZ',
+    'AO',
+    'AOL',
+    'APARTMENTS',
+    'APP',
+    'APPLE',
+    'AQ',
+    'AQUARELLE',
+    'AR',
+    'ARAB',
+    'ARAMCO',
+    'ARCHI',
+    'ARMY',
+    'ARPA',
+    'ART',
+    'ARTE',
+    'AS',
+    'ASDA',
+    'ASIA',
+    'ASSOCIATES',
+    'AT',
+    'ATHLETA',
+    'ATTORNEY',
+    'AU',
+    'AUCTION',
+    'AUDI',
+    'AUDIBLE',
+    'AUDIO',
+    'AUSPOST',
+    'AUTHOR',
+    'AUTO',
+    'AUTOS',
+    'AVIANCA',
+    'AW',
+    'AWS',
+    'AX',
+    'AXA',
+    'AZ',
+    'AZURE',
+    'BA',
+    'BABY',
+    'BAIDU',
+    'BANAMEX',
+    'BANANAREPUBLIC',
+    'BAND',
+    'BANK',
+    'BAR',
+    'BARCELONA',
+    'BARCLAYCARD',
+    'BARCLAYS',
+    'BAREFOOT',
+    'BARGAINS',
+    'BASEBALL',
+    'BASKETBALL',
+    'BAUHAUS',
+    'BAYERN',
+    'BB',
+    'BBC',
+    'BBT',
+    'BBVA',
+    'BCG',
+    'BCN',
+    'BD',
+    'BE',
+    'BEATS',
+    'BEAUTY',
+    'BEER',
+    'BENTLEY',
+    'BERLIN',
+    'BEST',
+    'BESTBUY',
+    'BET',
+    'BF',
+    'BG',
+    'BH',
+    'BHARTI',
+    'BI',
+    'BIBLE',
+    'BID',
+    'BIKE',
+    'BING',
+    'BINGO',
+    'BIO',
+    'BIZ',
+    'BJ',
+    'BLACK',
+    'BLACKFRIDAY',
+    'BLOCKBUSTER',
+    'BLOG',
+    'BLOOMBERG',
+    'BLUE',
+    'BM',
+    'BMS',
+    'BMW',
+    'BN',
+    'BNPPARIBAS',
+    'BO',
+    'BOATS',
+    'BOEHRINGER',
+    'BOFA',
+    'BOM',
+    'BOND',
+    'BOO',
+    'BOOK',
+    'BOOKING',
+    'BOSCH',
+    'BOSTIK',
+    'BOSTON',
+    'BOT',
+    'BOUTIQUE',
+    'BOX',
+    'BR',
+    'BRADESCO',
+    'BRIDGESTONE',
+    'BROADWAY',
+    'BROKER',
+    'BROTHER',
+    'BRUSSELS',
+    'BS',
+    'BT',
+    'BUDAPEST',
+    'BUGATTI',
+    'BUILD',
+    'BUILDERS',
+    'BUSINESS',
+    'BUY',
+    'BUZZ',
+    'BV',
+    'BW',
+    'BY',
+    'BZ',
+    'BZH',
+    'CA',
+    'CAB',
+    'CAFE',
+    'CAL',
+    'CALL',
+    'CALVINKLEIN',
+    'CAM',
+    'CAMERA',
+    'CAMP',
+    'CANCERRESEARCH',
+    'CANON',
+    'CAPETOWN',
+    'CAPITAL',
+    'CAPITALONE',
+    'CAR',
+    'CARAVAN',
+    'CARDS',
+    'CARE',
+    'CAREER',
+    'CAREERS',
+    'CARS',
+    'CARTIER',
+    'CASA',
+    'CASE',
+    'CASEIH',
+    'CASH',
+    'CASINO',
+    'CAT',
+    'CATERING',
+    'CATHOLIC',
+    'CBA',
+    'CBN',
+    'CBRE',
+    'CBS',
+    'CC',
+    'CD',
+    'CEB',
+    'CENTER',
+    'CEO',
+    'CERN',
+    'CF',
+    'CFA',
+    'CFD',
+    'CG',
+    'CH',
+    'CHANEL',
+    'CHANNEL',
+    'CHARITY',
+    'CHASE',
+    'CHAT',
+    'CHEAP',
+    'CHINTAI',
+    'CHRISTMAS',
+    'CHROME',
+    'CHRYSLER',
+    'CHURCH',
+    'CI',
+    'CIPRIANI',
+    'CIRCLE',
+    'CISCO',
+    'CITADEL',
+    'CITI',
+    'CITIC',
+    'CITY',
+    'CITYEATS',
+    'CK',
+    'CL',
+    'CLAIMS',
+    'CLEANING',
+    'CLICK',
+    'CLINIC',
+    'CLINIQUE',
+    'CLOTHING',
+    'CLOUD',
+    'CLUB',
+    'CLUBMED',
+    'CM',
+    'CN',
+    'CO',
+    'COACH',
+    'CODES',
+    'COFFEE',
+    'COLLEGE',
+    'COLOGNE',
+    'COM',
+    'COMCAST',
+    'COMMBANK',
+    'COMMUNITY',
+    'COMPANY',
+    'COMPARE',
+    'COMPUTER',
+    'COMSEC',
+    'CONDOS',
+    'CONSTRUCTION',
+    'CONSULTING',
+    'CONTACT',
+    'CONTRACTORS',
+    'COOKING',
+    'COOKINGCHANNEL',
+    'COOL',
+    'COOP',
+    'CORSICA',
+    'COUNTRY',
+    'COUPON',
+    'COUPONS',
+    'COURSES',
+    'CR',
+    'CREDIT',
+    'CREDITCARD',
+    'CREDITUNION',
+    'CRICKET',
+    'CROWN',
+    'CRS',
+    'CRUISE',
+    'CRUISES',
+    'CSC',
+    'CU',
+    'CUISINELLA',
+    'CV',
+    'CW',
+    'CX',
+    'CY',
+    'CYMRU',
+    'CYOU',
+    'CZ',
+    'DABUR',
+    'DAD',
+    'DANCE',
+    'DATA',
+    'DATE',
+    'DATING',
+    'DATSUN',
+    'DAY',
+    'DCLK',
+    'DDS',
+    'DE',
+    'DEAL',
+    'DEALER',
+    'DEALS',
+    'DEGREE',
+    'DELIVERY',
+    'DELL',
+    'DELOITTE',
+    'DELTA',
+    'DEMOCRAT',
+    'DENTAL',
+    'DENTIST',
+    'DESI',
+    'DESIGN',
+    'DEV',
+    'DHL',
+    'DIAMONDS',
+    'DIET',
+    'DIGITAL',
+    'DIRECT',
+    'DIRECTORY',
+    'DISCOUNT',
+    'DISCOVER',
+    'DISH',
+    'DIY',
+    'DJ',
+    'DK',
+    'DM',
+    'DNP',
+    'DO',
+    'DOCS',
+    'DOCTOR',
+    'DODGE',
+    'DOG',
+    'DOMAINS',
+    'DOT',
+    'DOWNLOAD',
+    'DRIVE',
+    'DTV',
+    'DUBAI',
+    'DUCK',
+    'DUNLOP',
+    'DUPONT',
+    'DURBAN',
+    'DVAG',
+    'DVR',
+    'DZ',
+    'EARTH',
+    'EAT',
+    'EC',
+    'ECO',
+    'EDEKA',
+    'EDU',
+    'EDUCATION',
+    'EE',
+    'EG',
+    'EMAIL',
+    'EMERCK',
+    'ENERGY',
+    'ENGINEER',
+    'ENGINEERING',
+    'ENTERPRISES',
+    'EPSON',
+    'EQUIPMENT',
+    'ER',
+    'ERICSSON',
+    'ERNI',
+    'ES',
+    'ESQ',
+    'ESTATE',
+    'ESURANCE',
+    'ET',
+    'ETISALAT',
+    'EU',
+    'EUROVISION',
+    'EUS',
+    'EVENTS',
+    'EVERBANK',
+    'EXCHANGE',
+    'EXPERT',
+    'EXPOSED',
+    'EXPRESS',
+    'EXTRASPACE',
+    'FAGE',
+    'FAIL',
+    'FAIRWINDS',
+    'FAITH',
+    'FAMILY',
+    'FAN',
+    'FANS',
+    'FARM',
+    'FARMERS',
+    'FASHION',
+    'FAST',
+    'FEDEX',
+    'FEEDBACK',
+    'FERRARI',
+    'FERRERO',
+    'FI',
+    'FIAT',
+    'FIDELITY',
+    'FIDO',
+    'FILM',
+    'FINAL',
+    'FINANCE',
+    'FINANCIAL',
+    'FIRE',
+    'FIRESTONE',
+    'FIRMDALE',
+    'FISH',
+    'FISHING',
+    'FIT',
+    'FITNESS',
+    'FJ',
+    'FK',
+    'FLICKR',
+    'FLIGHTS',
+    'FLIR',
+    'FLORIST',
+    'FLOWERS',
+    'FLY',
+    'FM',
+    'FO',
+    'FOO',
+    'FOOD',
+    'FOODNETWORK',
+    'FOOTBALL',
+    'FORD',
+    'FOREX',
+    'FORSALE',
+    'FORUM',
+    'FOUNDATION',
+    'FOX',
+    'FR',
+    'FREE',
+    'FRESENIUS',
+    'FRL',
+    'FROGANS',
+    'FRONTDOOR',
+    'FRONTIER',
+    'FTR',
+    'FUJITSU',
+    'FUJIXEROX',
+    'FUN',
+    'FUND',
+    'FURNITURE',
+    'FUTBOL',
+    'FYI',
+    'GA',
+    'GAL',
+    'GALLERY',
+    'GALLO',
+    'GALLUP',
+    'GAME',
+    'GAMES',
+    'GAP',
+    'GARDEN',
+    'GAY',
+    'GB',
+    'GBIZ',
+    'GD',
+    'GDN',
+    'GE',
+    'GEA',
+    'GENT',
+    'GENTING',
+    'GEORGE',
+    'GF',
+    'GG',
+    'GGEE',
+    'GH',
+    'GI',
+    'GIFT',
+    'GIFTS',
+    'GIVES',
+    'GIVING',
+    'GL',
+    'GLADE',
+    'GLASS',
+    'GLE',
+    'GLOBAL',
+    'GLOBO',
+    'GM',
+    'GMAIL',
+    'GMBH',
+    'GMO',
+    'GMX',
+    'GN',
+    'GODADDY',
+    'GOLD',
+    'GOLDPOINT',
+    'GOLF',
+    'GOO',
+    'GOODYEAR',
+    'GOOG',
+    'GOOGLE',
+    'GOP',
+    'GOT',
+    'GOV',
+    'GP',
+    'GQ',
+    'GR',
+    'GRAINGER',
+    'GRAPHICS',
+    'GRATIS',
+    'GREEN',
+    'GRIPE',
+    'GROCERY',
+    'GROUP',
+    'GS',
+    'GT',
+    'GU',
+    'GUARDIAN',
+    'GUCCI',
+    'GUGE',
+    'GUIDE',
+    'GUITARS',
+    'GURU',
+    'GW',
+    'GY',
+    'HAIR',
+    'HAMBURG',
+    'HANGOUT',
+    'HAUS',
+    'HBO',
+    'HDFC',
+    'HDFCBANK',
+    'HEALTH',
+    'HEALTHCARE',
+    'HELP',
+    'HELSINKI',
+    'HERE',
+    'HERMES',
+    'HGTV',
+    'HIPHOP',
+    'HISAMITSU',
+    'HITACHI',
+    'HIV',
+    'HK',
+    'HKT',
+    'HM',
+    'HN',
+    'HOCKEY',
+    'HOLDINGS',
+    'HOLIDAY',
+    'HOMEDEPOT',
+    'HOMEGOODS',
+    'HOMES',
+    'HOMESENSE',
+    'HONDA',
+    'HORSE',
+    'HOSPITAL',
+    'HOST',
+    'HOSTING',
+    'HOT',
+    'HOTELES',
+    'HOTELS',
+    'HOTMAIL',
+    'HOUSE',
+    'HOW',
+    'HR',
+    'HSBC',
+    'HT',
+    'HU',
+    'HUGHES',
+    'HYATT',
+    'HYUNDAI',
+    'IBM',
+    'ICBC',
+    'ICE',
+    'ICU',
+    'ID',
+    'IE',
+    'IEEE',
+    'IFM',
+    'IKANO',
+    'IL',
+    'IM',
+    'IMAMAT',
+    'IMDB',
+    'IMMO',
+    'IMMOBILIEN',
+    'IN',
+    'INC',
+    'INDUSTRIES',
+    'INFINITI',
+    'INFO',
+    'ING',
+    'INK',
+    'INSTITUTE',
+    'INSURANCE',
+    'INSURE',
+    'INT',
+    'INTEL',
+    'INTERNATIONAL',
+    'INTUIT',
+    'INVESTMENTS',
+    'IO',
+    'IPIRANGA',
+    'IQ',
+    'IR',
+    'IRISH',
+    'IS',
+    'ISMAILI',
+    'IST',
+    'ISTANBUL',
+    'IT',
+    'ITAU',
+    'ITV',
+    'IVECO',
+    'JAGUAR',
+    'JAVA',
+    'JCB',
+    'JCP',
+    'JE',
+    'JEEP',
+    'JETZT',
+    'JEWELRY',
+    'JIO',
+    'JLL',
+    'JM',
+    'JMP',
+    'JNJ',
+    'JO',
+    'JOBS',
+    'JOBURG',
+    'JOT',
+    'JOY',
+    'JP',
+    'JPMORGAN',
+    'JPRS',
+    'JUEGOS',
+    'JUNIPER',
+    'KAUFEN',
+    'KDDI',
+    'KE',
+    'KERRYHOTELS',
+    'KERRYLOGISTICS',
+    'KERRYPROPERTIES',
+    'KFH',
+    'KG',
+    'KH',
+    'KI',
+    'KIA',
+    'KIM',
+    'KINDER',
+    'KINDLE',
+    'KITCHEN',
+    'KIWI',
+    'KM',
+    'KN',
+    'KOELN',
+    'KOMATSU',
+    'KOSHER',
+    'KP',
+    'KPMG',
+    'KPN',
+    'KR',
+    'KRD',
+    'KRED',
+    'KUOKGROUP',
+    'KW',
+    'KY',
+    'KYOTO',
+    'KZ',
+    'LA',
+    'LACAIXA',
+    'LADBROKES',
+    'LAMBORGHINI',
+    'LAMER',
+    'LANCASTER',
+    'LANCIA',
+    'LANCOME',
+    'LAND',
+    'LANDROVER',
+    'LANXESS',
+    'LASALLE',
+    'LAT',
+    'LATINO',
+    'LATROBE',
+    'LAW',
+    'LAWYER',
+    'LB',
+    'LC',
+    'LDS',
+    'LEASE',
+    'LECLERC',
+    'LEFRAK',
+    'LEGAL',
+    'LEGO',
+    'LEXUS',
+    'LGBT',
+    'LI',
+    'LIAISON',
+    'LIDL',
+    'LIFE',
+    'LIFEINSURANCE',
+    'LIFESTYLE',
+    'LIGHTING',
+    'LIKE',
+    'LILLY',
+    'LIMITED',
+    'LIMO',
+    'LINCOLN',
+    'LINDE',
+    'LINK',
+    'LIPSY',
+    'LIVE',
+    'LIVING',
+    'LIXIL',
+    'LK',
+    'LLC',
+    'LOAN',
+    'LOANS',
+    'LOCKER',
+    'LOCUS',
+    'LOFT',
+    'LOL',
+    'LONDON',
+    'LOTTE',
+    'LOTTO',
+    'LOVE',
+    'LPL',
+    'LPLFINANCIAL',
+    'LR',
+    'LS',
+    'LT',
+    'LTD',
+    'LTDA',
+    'LU',
+    'LUNDBECK',
+    'LUPIN',
+    'LUXE',
+    'LUXURY',
+    'LV',
+    'LY',
+    'MA',
+    'MACYS',
+    'MADRID',
+    'MAIF',
+    'MAISON',
+    'MAKEUP',
+    'MAN',
+    'MANAGEMENT',
+    'MANGO',
+    'MAP',
+    'MARKET',
+    'MARKETING',
+    'MARKETS',
+    'MARRIOTT',
+    'MARSHALLS',
+    'MASERATI',
+    'MATTEL',
+    'MBA',
+    'MC',
+    'MCKINSEY',
+    'MD',
+    'ME',
+    'MED',
+    'MEDIA',
+    'MEET',
+    'MELBOURNE',
+    'MEME',
+    'MEMORIAL',
+    'MEN',
+    'MENU',
+    'MERCKMSD',
+    'METLIFE',
+    'MG',
+    'MH',
+    'MIAMI',
+    'MICROSOFT',
+    'MIL',
+    'MINI',
+    'MINT',
+    'MIT',
+    'MITSUBISHI',
+    'MK',
+    'ML',
+    'MLB',
+    'MLS',
+    'MM',
+    'MMA',
+    'MN',
+    'MO',
+    'MOBI',
+    'MOBILE',
+    'MODA',
+    'MOE',
+    'MOI',
+    'MOM',
+    'MONASH',
+    'MONEY',
+    'MONSTER',
+    'MOPAR',
+    'MORMON',
+    'MORTGAGE',
+    'MOSCOW',
+    'MOTO',
+    'MOTORCYCLES',
+    'MOV',
+    'MOVIE',
+    'MOVISTAR',
+    'MP',
+    'MQ',
+    'MR',
+    'MS',
+    'MSD',
+    'MT',
+    'MTN',
+    'MTR',
+    'MU',
+    'MUSEUM',
+    'MUTUAL',
+    'MV',
+    'MW',
+    'MX',
+    'MY',
+    'MZ',
+    'NA',
+    'NAB',
+    'NADEX',
+    'NAGOYA',
+    'NAME',
+    'NATIONWIDE',
+    'NATURA',
+    'NAVY',
+    'NBA',
+    'NC',
+    'NE',
+    'NEC',
+    'NET',
+    'NETBANK',
+    'NETFLIX',
+    'NETWORK',
+    'NEUSTAR',
+    'NEW',
+    'NEWHOLLAND',
+    'NEWS',
+    'NEXT',
+    'NEXTDIRECT',
+    'NEXUS',
+    'NF',
+    'NFL',
+    'NG',
+    'NGO',
+    'NHK',
+    'NI',
+    'NICO',
+    'NIKE',
+    'NIKON',
+    'NINJA',
+    'NISSAN',
+    'NISSAY',
+    'NL',
+    'NO',
+    'NOKIA',
+    'NORTHWESTERNMUTUAL',
+    'NORTON',
+    'NOW',
+    'NOWRUZ',
+    'NOWTV',
+    'NP',
+    'NR',
+    'NRA',
+    'NRW',
+    'NTT',
+    'NU',
+    'NYC',
+    'NZ',
+    'OBI',
+    'OBSERVER',
+    'OFF',
+    'OFFICE',
+    'OKINAWA',
+    'OLAYAN',
+    'OLAYANGROUP',
+    'OLDNAVY',
+    'OLLO',
+    'OM',
+    'OMEGA',
+    'ONE',
+    'ONG',
+    'ONL',
+    'ONLINE',
+    'ONYOURSIDE',
+    'OOO',
+    'OPEN',
+    'ORACLE',
+    'ORANGE',
+    'ORG',
+    'ORGANIC',
+    'ORIGINS',
+    'OSAKA',
+    'OTSUKA',
+    'OTT',
+    'OVH',
+    'PA',
+    'PAGE',
+    'PANASONIC',
+    'PARIS',
+    'PARS',
+    'PARTNERS',
+    'PARTS',
+    'PARTY',
+    'PASSAGENS',
+    'PAY',
+    'PCCW',
+    'PE',
+    'PET',
+    'PF',
+    'PFIZER',
+    'PG',
+    'PH',
+    'PHARMACY',
+    'PHD',
+    'PHILIPS',
+    'PHONE',
+    'PHOTO',
+    'PHOTOGRAPHY',
+    'PHOTOS',
+    'PHYSIO',
+    'PIAGET',
+    'PICS',
+    'PICTET',
+    'PICTURES',
+    'PID',
+    'PIN',
+    'PING',
+    'PINK',
+    'PIONEER',
+    'PIZZA',
+    'PK',
+    'PL',
+    'PLACE',
+    'PLAY',
+    'PLAYSTATION',
+    'PLUMBING',
+    'PLUS',
+    'PM',
+    'PN',
+    'PNC',
+    'POHL',
+    'POKER',
+    'POLITIE',
+    'PORN',
+    'POST',
+    'PR',
+    'PRAMERICA',
+    'PRAXI',
+    'PRESS',
+    'PRIME',
+    'PRO',
+    'PROD',
+    'PRODUCTIONS',
+    'PROF',
+    'PROGRESSIVE',
+    'PROMO',
+    'PROPERTIES',
+    'PROPERTY',
+    'PROTECTION',
+    'PRU',
+    'PRUDENTIAL',
+    'PS',
+    'PT',
+    'PUB',
+    'PW',
+    'PWC',
+    'PY',
+    'QA',
+    'QPON',
+    'QUEBEC',
+    'QUEST',
+    'QVC',
+    'RACING',
+    'RADIO',
+    'RAID',
+    'RE',
+    'READ',
+    'REALESTATE',
+    'REALTOR',
+    'REALTY',
+    'RECIPES',
+    'RED',
+    'REDSTONE',
+    'REDUMBRELLA',
+    'REHAB',
+    'REISE',
+    'REISEN',
+    'REIT',
+    'RELIANCE',
+    'REN',
+    'RENT',
+    'RENTALS',
+    'REPAIR',
+    'REPORT',
+    'REPUBLICAN',
+    'REST',
+    'RESTAURANT',
+    'REVIEW',
+    'REVIEWS',
+    'REXROTH',
+    'RICH',
+    'RICHARDLI',
+    'RICOH',
+    'RIGHTATHOME',
+    'RIL',
+    'RIO',
+    'RIP',
+    'RMIT',
+    'RO',
+    'ROCHER',
+    'ROCKS',
+    'RODEO',
+    'ROGERS',
+    'ROOM',
+    'RS',
+    'RSVP',
+    'RU',
+    'RUGBY',
+    'RUHR',
+    'RUN',
+    'RW',
+    'RWE',
+    'RYUKYU',
+    'SA',
+    'SAARLAND',
+    'SAFE',
+    'SAFETY',
+    'SAKURA',
+    'SALE',
+    'SALON',
+    'SAMSCLUB',
+    'SAMSUNG',
+    'SANDVIK',
+    'SANDVIKCOROMANT',
+    'SANOFI',
+    'SAP',
+    'SARL',
+    'SAS',
+    'SAVE',
+    'SAXO',
+    'SB',
+    'SBI',
+    'SBS',
+    'SC',
+    'SCA',
+    'SCB',
+    'SCHAEFFLER',
+    'SCHMIDT',
+    'SCHOLARSHIPS',
+    'SCHOOL',
+    'SCHULE',
+    'SCHWARZ',
+    'SCIENCE',
+    'SCJOHNSON',
+    'SCOR',
+    'SCOT',
+    'SD',
+    'SE',
+    'SEARCH',
+    'SEAT',
+    'SECURE',
+    'SECURITY',
+    'SEEK',
+    'SELECT',
+    'SENER',
+    'SERVICES',
+    'SES',
+    'SEVEN',
+    'SEW',
+    'SEX',
+    'SEXY',
+    'SFR',
+    'SG',
+    'SH',
+    'SHANGRILA',
+    'SHARP',
+    'SHAW',
+    'SHELL',
+    'SHIA',
+    'SHIKSHA',
+    'SHOES',
+    'SHOP',
+    'SHOPPING',
+    'SHOUJI',
+    'SHOW',
+    'SHOWTIME',
+    'SHRIRAM',
+    'SI',
+    'SILK',
+    'SINA',
+    'SINGLES',
+    'SITE',
+    'SJ',
+    'SK',
+    'SKI',
+    'SKIN',
+    'SKY',
+    'SKYPE',
+    'SL',
+    'SLING',
+    'SM',
+    'SMART',
+    'SMILE',
+    'SN',
+    'SNCF',
+    'SO',
+    'SOCCER',
+    'SOCIAL',
+    'SOFTBANK',
+    'SOFTWARE',
+    'SOHU',
+    'SOLAR',
+    'SOLUTIONS',
+    'SONG',
+    'SONY',
+    'SOY',
+    'SPACE',
+    'SPORT',
+    'SPOT',
+    'SPREADBETTING',
+    'SR',
+    'SRL',
+    'SRT',
+    'SS',
+    'ST',
+    'STADA',
+    'STAPLES',
+    'STAR',
+    'STATEBANK',
+    'STATEFARM',
+    'STC',
+    'STCGROUP',
+    'STOCKHOLM',
+    'STORAGE',
+    'STORE',
+    'STREAM',
+    'STUDIO',
+    'STUDY',
+    'STYLE',
+    'SU',
+    'SUCKS',
+    'SUPPLIES',
+    'SUPPLY',
+    'SUPPORT',
+    'SURF',
+    'SURGERY',
+    'SUZUKI',
+    'SV',
+    'SWATCH',
+    'SWIFTCOVER',
+    'SWISS',
+    'SX',
+    'SY',
+    'SYDNEY',
+    'SYMANTEC',
+    'SYSTEMS',
+    'SZ',
+    'TAB',
+    'TAIPEI',
+    'TALK',
+    'TAOBAO',
+    'TARGET',
+    'TATAMOTORS',
+    'TATAR',
+    'TATTOO',
+    'TAX',
+    'TAXI',
+    'TC',
+    'TCI',
+    'TD',
+    'TDK',
+    'TEAM',
+    'TECH',
+    'TECHNOLOGY',
+    'TEL',
+    'TELEFONICA',
+    'TEMASEK',
+    'TENNIS',
+    'TEVA',
+    'TF',
+    'TG',
+    'TH',
+    'THD',
+    'THEATER',
+    'THEATRE',
+    'TIAA',
+    'TICKETS',
+    'TIENDA',
+    'TIFFANY',
+    'TIPS',
+    'TIRES',
+    'TIROL',
+    'TJ',
+    'TJMAXX',
+    'TJX',
+    'TK',
+    'TKMAXX',
+    'TL',
+    'TM',
+    'TMALL',
+    'TN',
+    'TO',
+    'TODAY',
+    'TOKYO',
+    'TOOLS',
+    'TOP',
+    'TORAY',
+    'TOSHIBA',
+    'TOTAL',
+    'TOURS',
+    'TOWN',
+    'TOYOTA',
+    'TOYS',
+    'TR',
+    'TRADE',
+    'TRADING',
+    'TRAINING',
+    'TRAVEL',
+    'TRAVELCHANNEL',
+    'TRAVELERS',
+    'TRAVELERSINSURANCE',
+    'TRUST',
+    'TRV',
+    'TT',
+    'TUBE',
+    'TUI',
+    'TUNES',
+    'TUSHU',
+    'TV',
+    'TVS',
+    'TW',
+    'TZ',
+    'UA',
+    'UBANK',
+    'UBS',
+    'UCONNECT',
+    'UG',
+    'UK',
+    'UNICOM',
+    'UNIVERSITY',
+    'UNO',
+    'UOL',
+    'UPS',
+    'US',
+    'UY',
+    'UZ',
+    'VA',
+    'VACATIONS',
+    'VANA',
+    'VANGUARD',
+    'VC',
+    'VE',
+    'VEGAS',
+    'VENTURES',
+    'VERISIGN',
+    'VERSICHERUNG',
+    'VET',
+    'VG',
+    'VI',
+    'VIAJES',
+    'VIDEO',
+    'VIG',
+    'VIKING',
+    'VILLAS',
+    'VIN',
+    'VIP',
+    'VIRGIN',
+    'VISA',
+    'VISION',
+    'VISTAPRINT',
+    'VIVA',
+    'VIVO',
+    'VLAANDEREN',
+    'VN',
+    'VODKA',
+    'VOLKSWAGEN',
+    'VOLVO',
+    'VOTE',
+    'VOTING',
+    'VOTO',
+    'VOYAGE',
+    'VU',
+    'VUELOS',
+    'WALES',
+    'WALMART',
+    'WALTER',
+    'WANG',
+    'WANGGOU',
+    'WARMAN',
+    'WATCH',
+    'WATCHES',
+    'WEATHER',
+    'WEATHERCHANNEL',
+    'WEBCAM',
+    'WEBER',
+    'WEBSITE',
+    'WED',
+    'WEDDING',
+    'WEIBO',
+    'WEIR',
+    'WF',
+    'WHOSWHO',
+    'WIEN',
+    'WIKI',
+    'WILLIAMHILL',
+    'WIN',
+    'WINDOWS',
+    'WINE',
+    'WINNERS',
+    'WME',
+    'WOLTERSKLUWER',
+    'WOODSIDE',
+    'WORK',
+    'WORKS',
+    'WORLD',
+    'WOW',
+    'WS',
+    'WTC',
+    'WTF',
+    'XBOX',
+    'XEROX',
+    'XFINITY',
+    'XIHUAN',
+    'XIN',
+    'XN--11B4C3D',
+    'XN--1CK2E1B',
+    'XN--1QQW23A',
+    'XN--2SCRJ9C',
+    'XN--30RR7Y',
+    'XN--3BST00M',
+    'XN--3DS443G',
+    'XN--3E0B707E',
+    'XN--3HCRJ9C',
+    'XN--3OQ18VL8PN36A',
+    'XN--3PXU8K',
+    'XN--42C2D9A',
+    'XN--45BR5CYL',
+    'XN--45BRJ9C',
+    'XN--45Q11C',
+    'XN--4GBRIM',
+    'XN--54B7FTA0CC',
+    'XN--55QW42G',
+    'XN--55QX5D',
+    'XN--5SU34J936BGSG',
+    'XN--5TZM5G',
+    'XN--6FRZ82G',
+    'XN--6QQ986B3XL',
+    'XN--80ADXHKS',
+    'XN--80AO21A',
+    'XN--80AQECDR1A',
+    'XN--80ASEHDB',
+    'XN--80ASWG',
+    'XN--8Y0A063A',
+    'XN--90A3AC',
+    'XN--90AE',
+    'XN--90AIS',
+    'XN--9DBQ2A',
+    'XN--9ET52U',
+    'XN--9KRT00A',
+    'XN--B4W605FERD',
+    'XN--BCK1B9A5DRE4C',
+    'XN--C1AVG',
+    'XN--C2BR7G',
+    'XN--CCK2B3B',
+    'XN--CG4BKI',
+    'XN--CLCHC0EA0B2G2A9GCD',
+    'XN--CZR694B',
+    'XN--CZRS0T',
+    'XN--CZRU2D',
+    'XN--D1ACJ3B',
+    'XN--D1ALF',
+    'XN--E1A4C',
+    'XN--ECKVDTC9D',
+    'XN--EFVY88H',
+    'XN--ESTV75G',
+    'XN--FCT429K',
+    'XN--FHBEI',
+    'XN--FIQ228C5HS',
+    'XN--FIQ64B',
+    'XN--FIQS8S',
+    'XN--FIQZ9S',
+    'XN--FJQ720A',
+    'XN--FLW351E',
+    'XN--FPCRJ9C3D',
+    'XN--FZC2C9E2C',
+    'XN--FZYS8D69UVGM',
+    'XN--G2XX48C',
+    'XN--GCKR3F0F',
+    'XN--GECRJ9C',
+    'XN--GK3AT1E',
+    'XN--H2BREG3EVE',
+    'XN--H2BRJ9C',
+    'XN--H2BRJ9C8C',
+    'XN--HXT814E',
+    'XN--I1B6B1A6A2E',
+    'XN--IMR513N',
+    'XN--IO0A7I',
+    'XN--J1AEF',
+    'XN--J1AMH',
+    'XN--J6W193G',
+    'XN--JLQ61U9W7B',
+    'XN--JVR189M',
+    'XN--KCRX77D1X4A',
+    'XN--KPRW13D',
+    'XN--KPRY57D',
+    'XN--KPU716F',
+    'XN--KPUT3I',
+    'XN--L1ACC',
+    'XN--LGBBAT1AD8J',
+    'XN--MGB9AWBF',
+    'XN--MGBA3A3EJT',
+    'XN--MGBA3A4F16A',
+    'XN--MGBA7C0BBN0A',
+    'XN--MGBAAKC7DVF',
+    'XN--MGBAAM7A8H',
+    'XN--MGBAB2BD',
+    'XN--MGBAH1A3HJKRD',
+    'XN--MGBAI9AZGQP6J',
+    'XN--MGBAYH7GPA',
+    'XN--MGBBH1A',
+    'XN--MGBBH1A71E',
+    'XN--MGBC0A9AZCG',
+    'XN--MGBCA7DZDO',
+    'XN--MGBERP4A5D4AR',
+    'XN--MGBGU82A',
+    'XN--MGBI4ECEXP',
+    'XN--MGBPL2FH',
+    'XN--MGBT3DHD',
+    'XN--MGBTX2B',
+    'XN--MGBX4CD0AB',
+    'XN--MIX891F',
+    'XN--MK1BU44C',
+    'XN--MXTQ1M',
+    'XN--NGBC5AZD',
+    'XN--NGBE9E0A',
+    'XN--NGBRX',
+    'XN--NODE',
+    'XN--NQV7F',
+    'XN--NQV7FS00EMA',
+    'XN--NYQY26A',
+    'XN--O3CW4H',
+    'XN--OGBPF8FL',
+    'XN--OTU796D',
+    'XN--P1ACF',
+    'XN--P1AI',
+    'XN--PBT977C',
+    'XN--PGBS0DH',
+    'XN--PSSY2U',
+    'XN--Q9JYB4C',
+    'XN--QCKA1PMC',
+    'XN--QXA6A',
+    'XN--QXAM',
+    'XN--RHQV96G',
+    'XN--ROVU88B',
+    'XN--RVC1E0AM3E',
+    'XN--S9BRJ9C',
+    'XN--SES554G',
+    'XN--T60B56A',
+    'XN--TCKWE',
+    'XN--TIQ49XQYJ',
+    'XN--UNUP4Y',
+    'XN--VERMGENSBERATER-CTB',
+    'XN--VERMGENSBERATUNG-PWB',
+    'XN--VHQUV',
+    'XN--VUQ861B',
+    'XN--W4R85EL8FHU5DNRA',
+    'XN--W4RS40L',
+    'XN--WGBH1C',
+    'XN--WGBL6A',
+    'XN--XHQ521B',
+    'XN--XKC2AL3HYE2A',
+    'XN--XKC2DL3A5EE0H',
+    'XN--Y9A3AQ',
+    'XN--YFRO4I67O',
+    'XN--YGBI2AMMX',
+    'XN--ZFR164B',
+    'XXX',
+    'XYZ',
+    'YACHTS',
+    'YAHOO',
+    'YAMAXUN',
+    'YANDEX',
+    'YE',
+    'YODOBASHI',
+    'YOGA',
+    'YOKOHAMA',
+    'YOU',
+    'YOUTUBE',
+    'YT',
+    'YUN',
+    'ZA',
+    'ZAPPOS',
+    'ZARA',
+    'ZERO',
+    'ZIP',
+    'ZM',
+    'ZONE',
+    'ZUERICH',
+    'ZW'
+];
+
+
+// Keep as upper-case to make updating from source easier
+
+module.exports = new Set(internals.tlds.map((tld) => tld.toLowerCase()));
diff --git a/node_modules/@sideway/address/lib/uri.js b/node_modules/@sideway/address/lib/uri.js
new file mode 100644
index 00000000..f9791840
--- /dev/null
+++ b/node_modules/@sideway/address/lib/uri.js
@@ -0,0 +1,207 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const EscapeRegex = require('@hapi/hoek/lib/escapeRegex');
+
+
+const internals = {};
+
+
+internals.generate = function () {
+
+    const rfc3986 = {};
+
+    const hexDigit = '\\dA-Fa-f';                                               // HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+    const hexDigitOnly = '[' + hexDigit + ']';
+
+    const unreserved = '\\w-\\.~';                                              // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+    const subDelims = '!\\$&\'\\(\\)\\*\\+,;=';                                 // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+    const pctEncoded = '%' + hexDigit;                                          // pct-encoded = "%" HEXDIG HEXDIG
+    const pchar = unreserved + pctEncoded + subDelims + ':@';                   // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+    const pcharOnly = '[' + pchar + ']';
+    const decOctect = '(?:0{0,2}\\d|0?[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])';     // dec-octet = DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35  ; 0-9 / 10-99 / 100-199 / 200-249 / 250-255
+
+    rfc3986.ipv4address = '(?:' + decOctect + '\\.){3}' + decOctect;            // IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+
+    /*
+        h16 = 1*4HEXDIG ; 16 bits of address represented in hexadecimal
+        ls32 = ( h16 ":" h16 ) / IPv4address ; least-significant 32 bits of address
+        IPv6address =                            6( h16 ":" ) ls32
+                    /                       "::" 5( h16 ":" ) ls32
+                    / [               h16 ] "::" 4( h16 ":" ) ls32
+                    / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+                    / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+                    / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
+                    / [ *4( h16 ":" ) h16 ] "::"              ls32
+                    / [ *5( h16 ":" ) h16 ] "::"              h16
+                    / [ *6( h16 ":" ) h16 ] "::"
+    */
+
+    const h16 = hexDigitOnly + '{1,4}';
+    const ls32 = '(?:' + h16 + ':' + h16 + '|' + rfc3986.ipv4address + ')';
+    const IPv6SixHex = '(?:' + h16 + ':){6}' + ls32;
+    const IPv6FiveHex = '::(?:' + h16 + ':){5}' + ls32;
+    const IPv6FourHex = '(?:' + h16 + ')?::(?:' + h16 + ':){4}' + ls32;
+    const IPv6ThreeHex = '(?:(?:' + h16 + ':){0,1}' + h16 + ')?::(?:' + h16 + ':){3}' + ls32;
+    const IPv6TwoHex = '(?:(?:' + h16 + ':){0,2}' + h16 + ')?::(?:' + h16 + ':){2}' + ls32;
+    const IPv6OneHex = '(?:(?:' + h16 + ':){0,3}' + h16 + ')?::' + h16 + ':' + ls32;
+    const IPv6NoneHex = '(?:(?:' + h16 + ':){0,4}' + h16 + ')?::' + ls32;
+    const IPv6NoneHex2 = '(?:(?:' + h16 + ':){0,5}' + h16 + ')?::' + h16;
+    const IPv6NoneHex3 = '(?:(?:' + h16 + ':){0,6}' + h16 + ')?::';
+
+    rfc3986.ipv4Cidr = '(?:\\d|[1-2]\\d|3[0-2])';                                           // IPv4 cidr = DIGIT / %x31-32 DIGIT / "3" %x30-32  ; 0-9 / 10-29 / 30-32
+    rfc3986.ipv6Cidr = '(?:0{0,2}\\d|0?[1-9]\\d|1[01]\\d|12[0-8])';                         // IPv6 cidr = DIGIT / %x31-39 DIGIT / "1" %x0-1 DIGIT / "12" %x0-8;   0-9 / 10-99 / 100-119 / 120-128
+    rfc3986.ipv6address = '(?:' + IPv6SixHex + '|' + IPv6FiveHex + '|' + IPv6FourHex + '|' + IPv6ThreeHex + '|' + IPv6TwoHex + '|' + IPv6OneHex + '|' + IPv6NoneHex + '|' + IPv6NoneHex2 + '|' + IPv6NoneHex3 + ')';
+    rfc3986.ipvFuture = 'v' + hexDigitOnly + '+\\.[' + unreserved + subDelims + ':]+';      // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+
+    rfc3986.scheme = '[a-zA-Z][a-zA-Z\\d+-\\.]*';                                           // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+    rfc3986.schemeRegex = new RegExp(rfc3986.scheme);
+
+    const userinfo = '[' + unreserved + pctEncoded + subDelims + ':]*';                     // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+    const IPLiteral = '\\[(?:' + rfc3986.ipv6address + '|' + rfc3986.ipvFuture + ')\\]';    // IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
+    const regName = '[' + unreserved + pctEncoded + subDelims + ']{1,255}';                 // reg-name = *( unreserved / pct-encoded / sub-delims )
+    const host = '(?:' + IPLiteral + '|' + rfc3986.ipv4address + '|' + regName + ')';       // host = IP-literal / IPv4address / reg-name
+    const port = '\\d*';                                                                    // port = *DIGIT
+    const authority = '(?:' + userinfo + '@)?' + host + '(?::' + port + ')?';               // authority   = [ userinfo "@" ] host [ ":" port ]
+    const authorityCapture = '(?:' + userinfo + '@)?(' + host + ')(?::' + port + ')?';
+
+    /*
+        segment       = *pchar
+        segment-nz    = 1*pchar
+        path          = path-abempty    ; begins with "/" '|' is empty
+                    / path-absolute   ; begins with "/" but not "//"
+                    / path-noscheme   ; begins with a non-colon segment
+                    / path-rootless   ; begins with a segment
+                    / path-empty      ; zero characters
+        path-abempty  = *( "/" segment )
+        path-absolute = "/" [ segment-nz *( "/" segment ) ]
+        path-rootless = segment-nz *( "/" segment )
+    */
+
+    const segment = pcharOnly + '*';
+    const segmentNz = pcharOnly + '+';
+    const segmentNzNc = '[' + unreserved + pctEncoded + subDelims + '@' + ']+';
+    const pathEmpty = '';
+    const pathAbEmpty = '(?:\\/' + segment + ')*';
+    const pathAbsolute = '\\/(?:' + segmentNz + pathAbEmpty + ')?';
+    const pathRootless = segmentNz + pathAbEmpty;
+    const pathNoScheme = segmentNzNc + pathAbEmpty;
+    const pathAbNoAuthority = '(?:\\/\\/\\/' + segment + pathAbEmpty + ')';     // Used by file:///
+
+    // hier-part = "//" authority path
+
+    rfc3986.hierPart = '(?:' + '(?:\\/\\/' + authority + pathAbEmpty + ')' + '|' + pathAbsolute + '|' + pathRootless + '|' + pathAbNoAuthority + ')';
+    rfc3986.hierPartCapture = '(?:' + '(?:\\/\\/' + authorityCapture + pathAbEmpty + ')' + '|' + pathAbsolute + '|' + pathRootless + ')';
+
+    // relative-part = "//" authority path-abempty / path-absolute / path-noscheme / path-empty
+
+    rfc3986.relativeRef = '(?:' + '(?:\\/\\/' + authority + pathAbEmpty + ')' + '|' + pathAbsolute + '|' + pathNoScheme + '|' + pathEmpty + ')';
+    rfc3986.relativeRefCapture = '(?:' + '(?:\\/\\/' + authorityCapture + pathAbEmpty + ')' + '|' + pathAbsolute + '|' + pathNoScheme + '|' + pathEmpty + ')';
+
+    // query = *( pchar / "/" / "?" )
+    // query = *( pchar / "[" / "]" / "/" / "?" )
+
+    rfc3986.query = '[' + pchar + '\\/\\?]*(?=#|$)';                            //Finish matching either at the fragment part '|' end of the line.
+    rfc3986.queryWithSquareBrackets = '[' + pchar + '\\[\\]\\/\\?]*(?=#|$)';
+
+    // fragment = *( pchar / "/" / "?" )
+
+    rfc3986.fragment = '[' + pchar + '\\/\\?]*';
+
+    return rfc3986;
+};
+
+internals.rfc3986 = internals.generate();
+
+
+exports.ip = {
+    v4Cidr: internals.rfc3986.ipv4Cidr,
+    v6Cidr: internals.rfc3986.ipv6Cidr,
+    ipv4: internals.rfc3986.ipv4address,
+    ipv6: internals.rfc3986.ipv6address,
+    ipvfuture: internals.rfc3986.ipvFuture
+};
+
+
+internals.createRegex = function (options) {
+
+    const rfc = internals.rfc3986;
+
+    // Construct expression
+
+    const query = options.allowQuerySquareBrackets ? rfc.queryWithSquareBrackets : rfc.query;
+    const suffix = '(?:\\?' + query + ')?' + '(?:#' + rfc.fragment + ')?';
+
+    // relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+
+    const relative = options.domain ? rfc.relativeRefCapture : rfc.relativeRef;
+
+    if (options.relativeOnly) {
+        return internals.wrap(relative + suffix);
+    }
+
+    // Custom schemes
+
+    let customScheme = '';
+    if (options.scheme) {
+        Assert(options.scheme instanceof RegExp || typeof options.scheme === 'string' || Array.isArray(options.scheme), 'scheme must be a RegExp, String, or Array');
+
+        const schemes = [].concat(options.scheme);
+        Assert(schemes.length >= 1, 'scheme must have at least 1 scheme specified');
+
+        // Flatten the array into a string to be used to match the schemes
+
+        const selections = [];
+        for (let i = 0; i < schemes.length; ++i) {
+            const scheme = schemes[i];
+            Assert(scheme instanceof RegExp || typeof scheme === 'string', 'scheme at position ' + i + ' must be a RegExp or String');
+
+            if (scheme instanceof RegExp) {
+                selections.push(scheme.source.toString());
+            }
+            else {
+                Assert(rfc.schemeRegex.test(scheme), 'scheme at position ' + i + ' must be a valid scheme');
+                selections.push(EscapeRegex(scheme));
+            }
+        }
+
+        customScheme = selections.join('|');
+    }
+
+    // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+    const scheme = customScheme ? '(?:' + customScheme + ')' : rfc.scheme;
+    const absolute = '(?:' + scheme + ':' + (options.domain ? rfc.hierPartCapture : rfc.hierPart) + ')';
+    const prefix = options.allowRelative ? '(?:' + absolute + '|' + relative + ')' : absolute;
+    return internals.wrap(prefix + suffix, customScheme);
+};
+
+
+internals.wrap = function (raw, scheme) {
+
+    raw = `(?=.)(?!https?\:/$)${raw}`;              // Require at least one character and explicitly forbid 'http:/'
+
+    return {
+        raw,
+        regex: new RegExp(`^${raw}$`),
+        scheme
+    };
+};
+
+
+internals.uriRegex = internals.createRegex({});
+
+
+exports.regex = function (options = {}) {
+
+    if (options.scheme ||
+        options.allowRelative ||
+        options.relativeOnly ||
+        options.allowQuerySquareBrackets ||
+        options.domain) {
+
+        return internals.createRegex(options);
+    }
+
+    return internals.uriRegex;
+};
diff --git a/node_modules/@sideway/address/package.json b/node_modules/@sideway/address/package.json
new file mode 100644
index 00000000..610bc93d
--- /dev/null
+++ b/node_modules/@sideway/address/package.json
@@ -0,0 +1,63 @@
+{
+  "_from": "@sideway/address@^4.1.0",
+  "_id": "@sideway/address@4.1.0",
+  "_inBundle": false,
+  "_integrity": "sha512-wAH/JYRXeIFQRsxerIuLjgUu2Xszam+O5xKeatJ4oudShOOirfmsQ1D6LL54XOU2tizpCYku+s1wmU0SYdpoSA==",
+  "_location": "/@sideway/address",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "@sideway/address@^4.1.0",
+    "name": "@sideway/address",
+    "escapedName": "@sideway%2faddress",
+    "scope": "@sideway",
+    "rawSpec": "^4.1.0",
+    "saveSpec": null,
+    "fetchSpec": "^4.1.0"
+  },
+  "_requiredBy": [
+    "/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.0.tgz",
+  "_shasum": "0b301ada10ac4e0e3fa525c90615e0b61a72b78d",
+  "_spec": "@sideway/address@^4.1.0",
+  "_where": "C:\\Users\\V S THARUNIKA\\Documents\\book-racker\\node_modules\\joi",
+  "bugs": {
+    "url": "https://github.com/sideway/address/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "@hapi/hoek": "^9.0.0"
+  },
+  "deprecated": false,
+  "description": "Email address and domain validation",
+  "devDependencies": {
+    "@hapi/code": "8.x.x",
+    "@hapi/lab": "24.x.x",
+    "typescript": "4.0.x"
+  },
+  "files": [
+    "lib"
+  ],
+  "homepage": "https://github.com/sideway/address#readme",
+  "keywords": [
+    "email",
+    "domain",
+    "address",
+    "validation"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "@sideway/address",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/sideway/address.git"
+  },
+  "scripts": {
+    "test": "lab -a @hapi/code -t 100 -L -Y",
+    "test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
+  },
+  "types": "lib/index.d.ts",
+  "version": "4.1.0"
+}
diff --git a/node_modules/@sideway/formula/LICENSE.md b/node_modules/@sideway/formula/LICENSE.md
new file mode 100644
index 00000000..995d3407
--- /dev/null
+++ b/node_modules/@sideway/formula/LICENSE.md
@@ -0,0 +1,9 @@
+Copyright (c) 2019-2020, Sideway. Inc, and project contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * 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.
+ * The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 HOLDERS AND 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/node_modules/@sideway/formula/README.md b/node_modules/@sideway/formula/README.md
new file mode 100644
index 00000000..13da3afa
--- /dev/null
+++ b/node_modules/@sideway/formula/README.md
@@ -0,0 +1,18 @@
+# @sideway/formula
+
+#### Math and string formula parser.
+
+**formula** is part of the **joi** ecosystem.
+
+### Visit the [joi.dev](https://joi.dev) Developer Portal for tutorials, documentation, and support
+
+## Useful resources
+
+- [Documentation and API](https://joi.dev/module/formula/)
+- [Version status](https://joi.dev/resources/status/#formula) (builds, dependencies, node versions, licenses, eol)
+- [Changelog](https://joi.dev/module/formula/changelog/)
+- [Project policies](https://joi.dev/policies/)
+
+## Acknowledgements
+
+Inspired by [**fparse**](https://github.com/bylexus/fparse), copyright 2012-2018 Alexander Schenkel <alex@alexi.ch>
diff --git a/node_modules/@sideway/formula/lib/index.d.ts b/node_modules/@sideway/formula/lib/index.d.ts
new file mode 100644
index 00000000..d78cc1d4
--- /dev/null
+++ b/node_modules/@sideway/formula/lib/index.d.ts
@@ -0,0 +1,52 @@
+/**
+ * Formula parser
+ */
+export class Parser<T extends (string | number)> {
+
+    /**
+     * Create a new formula parser.
+     * 
+     * @param formula - the formula string to parse.
+     * @param options - optional settings.
+     */
+    constructor(formula: string, options?: Options);
+
+    /**
+     * Evaluate the formula.
+     * 
+     * @param context - optional object with runtime formula context used to resolve variables.
+     * 
+     * @returns the string or number outcome of the resolved formula.
+     */
+    evaluate(context?: any): T;
+}
+
+
+export interface Options {
+
+    /**
+     * A hash of key - value pairs used to convert constants to values.
+     */
+    readonly constants?: Record<string, any>;
+
+    /**
+     * A regular expression used to validate token variables.
+     */
+    readonly tokenRx?: RegExp;
+
+    /**
+     * A variable resolver factory function.
+     */
+    readonly reference?: Options.Reference;
+
+    /**
+     * A hash of key-value pairs used to resolve formula functions.
+     */
+    readonly functions?: Record<string, Function>;
+}
+
+
+export namespace Options {
+
+    type Reference = (name: string) => (context: any) => any;
+}
diff --git a/node_modules/@sideway/formula/lib/index.js b/node_modules/@sideway/formula/lib/index.js
new file mode 100644
index 00000000..871ab1bb
--- /dev/null
+++ b/node_modules/@sideway/formula/lib/index.js
@@ -0,0 +1,456 @@
+'use strict';
+
+const internals = {
+    operators: ['!', '^', '*', '/', '%', '+', '-', '<', '<=', '>', '>=', '==', '!=', '&&', '||', '??'],
+    operatorCharacters: ['!', '^', '*', '/', '%', '+', '-', '<', '=', '>', '&', '|', '?'],
+    operatorsOrder: [['^'], ['*', '/', '%'], ['+', '-'], ['<', '<=', '>', '>='], ['==', '!='], ['&&'], ['||', '??']],
+    operatorsPrefix: ['!', 'n'],
+
+    literals: {
+        '"': '"',
+        '`': '`',
+        '\'': '\'',
+        '[': ']'
+    },
+
+    numberRx: /^(?:[0-9]*\.?[0-9]*){1}$/,
+    tokenRx: /^[\w\$\#\.\@\:\{\}]+$/,
+
+    symbol: Symbol('formula'),
+    settings: Symbol('settings')
+};
+
+
+exports.Parser = class {
+
+    constructor(string, options = {}) {
+
+        if (!options[internals.settings] &&
+            options.constants) {
+
+            for (const constant in options.constants) {
+                const value = options.constants[constant];
+                if (value !== null &&
+                    !['boolean', 'number', 'string'].includes(typeof value)) {
+
+                    throw new Error(`Formula constant ${constant} contains invalid ${typeof value} value type`);
+                }
+            }
+        }
+
+        this.settings = options[internals.settings] ? options : Object.assign({ [internals.settings]: true, constants: {}, functions: {} }, options);
+        this.single = null;
+
+        this._parts = null;
+        this._parse(string);
+    }
+
+    _parse(string) {
+
+        let parts = [];
+        let current = '';
+        let parenthesis = 0;
+        let literal = false;
+
+        const flush = (inner) => {
+
+            if (parenthesis) {
+                throw new Error('Formula missing closing parenthesis');
+            }
+
+            const last = parts.length ? parts[parts.length - 1] : null;
+
+            if (!literal &&
+                !current &&
+                !inner) {
+
+                return;
+            }
+
+            if (last &&
+                last.type === 'reference' &&
+                inner === ')') {                                                                // Function
+
+                last.type = 'function';
+                last.value = this._subFormula(current, last.value);
+                current = '';
+                return;
+            }
+
+            if (inner === ')') {                                                                // Segment
+                const sub = new exports.Parser(current, this.settings);
+                parts.push({ type: 'segment', value: sub });
+            }
+            else if (literal) {
+                if (literal === ']') {                                                          // Reference
+                    parts.push({ type: 'reference', value: current });
+                    current = '';
+                    return;
+                }
+
+                parts.push({ type: 'literal', value: current });                                // Literal
+            }
+            else if (internals.operatorCharacters.includes(current)) {                          // Operator
+                if (last &&
+                    last.type === 'operator' &&
+                    internals.operators.includes(last.value + current)) {                       // 2 characters operator
+
+                    last.value += current;
+                }
+                else {
+                    parts.push({ type: 'operator', value: current });
+                }
+            }
+            else if (current.match(internals.numberRx)) {                                       // Number
+                parts.push({ type: 'constant', value: parseFloat(current) });
+            }
+            else if (this.settings.constants[current] !== undefined) {                          // Constant
+                parts.push({ type: 'constant', value: this.settings.constants[current] });
+            }
+            else {                                                                              // Reference
+                if (!current.match(internals.tokenRx)) {
+                    throw new Error(`Formula contains invalid token: ${current}`);
+                }
+
+                parts.push({ type: 'reference', value: current });
+            }
+
+            current = '';
+        };
+
+        for (const c of string) {
+            if (literal) {
+                if (c === literal) {
+                    flush();
+                    literal = false;
+                }
+                else {
+                    current += c;
+                }
+            }
+            else if (parenthesis) {
+                if (c === '(') {
+                    current += c;
+                    ++parenthesis;
+                }
+                else if (c === ')') {
+                    --parenthesis;
+                    if (!parenthesis) {
+                        flush(c);
+                    }
+                    else {
+                        current += c;
+                    }
+                }
+                else {
+                    current += c;
+                }
+            }
+            else if (c in internals.literals) {
+                literal = internals.literals[c];
+            }
+            else if (c === '(') {
+                flush();
+                ++parenthesis;
+            }
+            else if (internals.operatorCharacters.includes(c)) {
+                flush();
+                current = c;
+                flush();
+            }
+            else if (c !== ' ') {
+                current += c;
+            }
+            else {
+                flush();
+            }
+        }
+
+        flush();
+
+        // Replace prefix - to internal negative operator
+
+        parts = parts.map((part, i) => {
+
+            if (part.type !== 'operator' ||
+                part.value !== '-' ||
+                i && parts[i - 1].type !== 'operator') {
+
+                return part;
+            }
+
+            return { type: 'operator', value: 'n' };
+        });
+
+        // Validate tokens order
+
+        let operator = false;
+        for (const part of parts) {
+            if (part.type === 'operator') {
+                if (internals.operatorsPrefix.includes(part.value)) {
+                    continue;
+                }
+
+                if (!operator) {
+                    throw new Error('Formula contains an operator in invalid position');
+                }
+
+                if (!internals.operators.includes(part.value)) {
+                    throw new Error(`Formula contains an unknown operator ${part.value}`);
+                }
+            }
+            else if (operator) {
+                throw new Error('Formula missing expected operator');
+            }
+
+            operator = !operator;
+        }
+
+        if (!operator) {
+            throw new Error('Formula contains invalid trailing operator');
+        }
+
+        // Identify single part
+
+        if (parts.length === 1 &&
+            ['reference', 'literal', 'constant'].includes(parts[0].type)) {
+
+            this.single = { type: parts[0].type === 'reference' ? 'reference' : 'value', value: parts[0].value };
+        }
+
+        // Process parts
+
+        this._parts = parts.map((part) => {
+
+            // Operators
+
+            if (part.type === 'operator') {
+                return internals.operatorsPrefix.includes(part.value) ? part : part.value;
+            }
+
+            // Literals, constants, segments
+
+            if (part.type !== 'reference') {
+                return part.value;
+            }
+
+            // References
+
+            if (this.settings.tokenRx &&
+                !this.settings.tokenRx.test(part.value)) {
+
+                throw new Error(`Formula contains invalid reference ${part.value}`);
+            }
+
+            if (this.settings.reference) {
+                return this.settings.reference(part.value);
+            }
+
+            return internals.reference(part.value);
+        });
+    }
+
+    _subFormula(string, name) {
+
+        const method = this.settings.functions[name];
+        if (typeof method !== 'function') {
+            throw new Error(`Formula contains unknown function ${name}`);
+        }
+
+        let args = [];
+        if (string) {
+            let current = '';
+            let parenthesis = 0;
+            let literal = false;
+
+            const flush = () => {
+
+                if (!current) {
+                    throw new Error(`Formula contains function ${name} with invalid arguments ${string}`);
+                }
+
+                args.push(current);
+                current = '';
+            };
+
+            for (let i = 0; i < string.length; ++i) {
+                const c = string[i];
+                if (literal) {
+                    current += c;
+                    if (c === literal) {
+                        literal = false;
+                    }
+                }
+                else if (c in internals.literals &&
+                    !parenthesis) {
+
+                    current += c;
+                    literal = internals.literals[c];
+                }
+                else if (c === ',' &&
+                    !parenthesis) {
+
+                    flush();
+                }
+                else {
+                    current += c;
+                    if (c === '(') {
+                        ++parenthesis;
+                    }
+                    else if (c === ')') {
+                        --parenthesis;
+                    }
+                }
+            }
+
+            flush();
+        }
+
+        args = args.map((arg) => new exports.Parser(arg, this.settings));
+
+        return function (context) {
+
+            const innerValues = [];
+            for (const arg of args) {
+                innerValues.push(arg.evaluate(context));
+            }
+
+            return method.call(context, ...innerValues);
+        };
+    }
+
+    evaluate(context) {
+
+        const parts = this._parts.slice();
+
+        // Prefix operators
+
+        for (let i = parts.length - 2; i >= 0; --i) {
+            const part = parts[i];
+            if (part &&
+                part.type === 'operator') {
+
+                const current = parts[i + 1];
+                parts.splice(i + 1, 1);
+                const value = internals.evaluate(current, context);
+                parts[i] = internals.single(part.value, value);
+            }
+        }
+
+        // Left-right operators
+
+        internals.operatorsOrder.forEach((set) => {
+
+            for (let i = 1; i < parts.length - 1;) {
+                if (set.includes(parts[i])) {
+                    const operator = parts[i];
+                    const left = internals.evaluate(parts[i - 1], context);
+                    const right = internals.evaluate(parts[i + 1], context);
+
+                    parts.splice(i, 2);
+                    const result = internals.calculate(operator, left, right);
+                    parts[i - 1] = result === 0 ? 0 : result;                               // Convert -0
+                }
+                else {
+                    i += 2;
+                }
+            }
+        });
+
+        return internals.evaluate(parts[0], context);
+    }
+};
+
+
+exports.Parser.prototype[internals.symbol] = true;
+
+
+internals.reference = function (name) {
+
+    return function (context) {
+
+        return context && context[name] !== undefined ? context[name] : null;
+    };
+};
+
+
+internals.evaluate = function (part, context) {
+
+    if (part === null) {
+        return null;
+    }
+
+    if (typeof part === 'function') {
+        return part(context);
+    }
+
+    if (part[internals.symbol]) {
+        return part.evaluate(context);
+    }
+
+    return part;
+};
+
+
+internals.single = function (operator, value) {
+
+    if (operator === '!') {
+        return value ? false : true;
+    }
+
+    // operator === 'n'
+
+    const negative = -value;
+    if (negative === 0) {       // Override -0
+        return 0;
+    }
+
+    return negative;
+};
+
+
+internals.calculate = function (operator, left, right) {
+
+    if (operator === '??') {
+        return internals.exists(left) ? left : right;
+    }
+
+    if (typeof left === 'string' ||
+        typeof right === 'string') {
+
+        if (operator === '+') {
+            left = internals.exists(left) ? left : '';
+            right = internals.exists(right) ? right : '';
+            return left + right;
+        }
+    }
+    else {
+        switch (operator) {
+            case '^': return Math.pow(left, right);
+            case '*': return left * right;
+            case '/': return left / right;
+            case '%': return left % right;
+            case '+': return left + right;
+            case '-': return left - right;
+        }
+    }
+
+    switch (operator) {
+        case '<': return left < right;
+        case '<=': return left <= right;
+        case '>': return left > right;
+        case '>=': return left >= right;
+        case '==': return left === right;
+        case '!=': return left !== right;
+        case '&&': return left && right;
+        case '||': return left || right;
+    }
+
+    return null;
+};
+
+
+internals.exists = function (value) {
+
+    return value !== null && value !== undefined;
+};
diff --git a/node_modules/@sideway/formula/package.json b/node_modules/@sideway/formula/package.json
new file mode 100644
index 00000000..5423c7a3
--- /dev/null
+++ b/node_modules/@sideway/formula/package.json
@@ -0,0 +1,61 @@
+{
+  "_from": "@sideway/formula@^3.0.0",
+  "_id": "@sideway/formula@3.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
+  "_location": "/@sideway/formula",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "@sideway/formula@^3.0.0",
+    "name": "@sideway/formula",
+    "escapedName": "@sideway%2fformula",
+    "scope": "@sideway",
+    "rawSpec": "^3.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.0"
+  },
+  "_requiredBy": [
+    "/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
+  "_shasum": "fe158aee32e6bd5de85044be615bc08478a0a13c",
+  "_spec": "@sideway/formula@^3.0.0",
+  "_where": "C:\\Users\\V S THARUNIKA\\Documents\\book-racker\\node_modules\\joi",
+  "bugs": {
+    "url": "https://github.com/sideway/formula/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Math and string formula parser.",
+  "devDependencies": {
+    "@hapi/code": "8.x.x",
+    "@hapi/lab": "24.x.x",
+    "typescript": "4.0.x"
+  },
+  "files": [
+    "lib"
+  ],
+  "homepage": "https://github.com/sideway/formula#readme",
+  "keywords": [
+    "formula",
+    "parser",
+    "math",
+    "string"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "@sideway/formula",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/sideway/formula.git"
+  },
+  "scripts": {
+    "test": "lab -a @hapi/code -t 100 -L -Y",
+    "test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
+  },
+  "types": "lib/index.d.ts",
+  "version": "3.0.0"
+}
diff --git a/node_modules/@sideway/pinpoint/LICENSE.md b/node_modules/@sideway/pinpoint/LICENSE.md
new file mode 100644
index 00000000..f0dfb171
--- /dev/null
+++ b/node_modules/@sideway/pinpoint/LICENSE.md
@@ -0,0 +1,10 @@
+Copyright (c) 2019-2020, Sideway. Inc, and project contributors  
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+* 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.
+* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 HOLDERS AND 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 OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/@sideway/pinpoint/README.md b/node_modules/@sideway/pinpoint/README.md
new file mode 100644
index 00000000..2996c821
--- /dev/null
+++ b/node_modules/@sideway/pinpoint/README.md
@@ -0,0 +1,14 @@
+# @sideway/pinpoint
+
+#### Return the filename and line number of the calling function.
+
+**pinpoint** is part of the **joi** ecosystem.
+
+### Visit the [joi.dev](https://joi.dev) Developer Portal for tutorials, documentation, and support
+
+## Useful resources
+
+- [Documentation and API](https://joi.dev/module/pinpoint/)
+- [Version status](https://joi.dev/resources/status/#pinpoint) (builds, dependencies, node versions, licenses, eol)
+- [Changelog](https://joi.dev/module/pinpoint/changelog/)
+- [Project policies](https://joi.dev/policies/)
diff --git a/node_modules/@sideway/pinpoint/lib/index.d.ts b/node_modules/@sideway/pinpoint/lib/index.d.ts
new file mode 100644
index 00000000..38fadaa3
--- /dev/null
+++ b/node_modules/@sideway/pinpoint/lib/index.d.ts
@@ -0,0 +1,24 @@
+/**
+Returns the filename and line number of the caller in the call stack
+
+@param depth - The distance from the location function in the call stack. Defaults to 1 (caller).
+
+@return an object with the filename and line number.
+*/
+export function location(depth?: number): location.Location;
+
+declare namespace location {
+
+    interface Location {
+
+        /**
+        The fully qualified filename.
+        */
+        readonly filename: string;
+
+        /**
+        The file line number.
+        */
+        readonly line: number;
+    }
+}
diff --git a/node_modules/@sideway/pinpoint/lib/index.js b/node_modules/@sideway/pinpoint/lib/index.js
new file mode 100644
index 00000000..48205509
--- /dev/null
+++ b/node_modules/@sideway/pinpoint/lib/index.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const internals = {};
+
+
+exports.location = function (depth = 0) {
+
+    const orig = Error.prepareStackTrace;
+    Error.prepareStackTrace = (ignore, stack) => stack;
+
+    const capture = {};
+    Error.captureStackTrace(capture, this);
+    const line = capture.stack[depth + 1];
+
+    Error.prepareStackTrace = orig;
+
+    return {
+        filename: line.getFileName(),
+        line: line.getLineNumber()
+    };
+};
diff --git a/node_modules/@sideway/pinpoint/package.json b/node_modules/@sideway/pinpoint/package.json
new file mode 100644
index 00000000..d5a46c0b
--- /dev/null
+++ b/node_modules/@sideway/pinpoint/package.json
@@ -0,0 +1,58 @@
+{
+  "_from": "@sideway/pinpoint@^2.0.0",
+  "_id": "@sideway/pinpoint@2.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
+  "_location": "/@sideway/pinpoint",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "@sideway/pinpoint@^2.0.0",
+    "name": "@sideway/pinpoint",
+    "escapedName": "@sideway%2fpinpoint",
+    "scope": "@sideway",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
+  "_shasum": "cff8ffadc372ad29fd3f78277aeb29e632cc70df",
+  "_spec": "@sideway/pinpoint@^2.0.0",
+  "_where": "C:\\Users\\V S THARUNIKA\\Documents\\book-racker\\node_modules\\joi",
+  "bugs": {
+    "url": "https://github.com/sideway/pinpoint/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Return the filename and line number of the calling function",
+  "devDependencies": {
+    "@hapi/code": "8.x.x",
+    "@hapi/lab": "24.x.x",
+    "typescript": "4.0.x"
+  },
+  "files": [
+    "lib"
+  ],
+  "homepage": "https://github.com/sideway/pinpoint#readme",
+  "keywords": [
+    "utilities"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "@sideway/pinpoint",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/sideway/pinpoint.git"
+  },
+  "scripts": {
+    "test": "lab -a @hapi/code -t 100 -L -Y",
+    "test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
+  },
+  "types": "lib/index.d.ts",
+  "version": "2.0.0"
+}
diff --git a/node_modules/joi/LICENSE.md b/node_modules/joi/LICENSE.md
new file mode 100644
index 00000000..35577405
--- /dev/null
+++ b/node_modules/joi/LICENSE.md
@@ -0,0 +1,10 @@
+Copyright (c) 2012-2020, Sideway. Inc, and project contributors.<br>
+Copyright (c) 2012-2014, Walmart.<br>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+* 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.
+* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 HOLDERS AND 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/node_modules/joi/README.md b/node_modules/joi/README.md
new file mode 100644
index 00000000..c5f092fb
--- /dev/null
+++ b/node_modules/joi/README.md
@@ -0,0 +1,15 @@
+# joi
+
+#### The most powerful schema description language and data validator for JavaScript.
+
+## Installation
+`npm install joi`
+
+### Visit the [joi.dev](https://joi.dev) Developer Portal for tutorials, documentation, and support
+
+## Useful resources
+
+- [Documentation and API](https://joi.dev/api/)
+- [Versions status](https://joi.dev/resources/status/#joi)
+- [Changelog](https://joi.dev/resources/changelog/)
+- [Project policies](https://joi.dev/policies/)
diff --git a/node_modules/joi/dist/joi-browser.min.js b/node_modules/joi/dist/joi-browser.min.js
new file mode 100644
index 00000000..6a0ae250
--- /dev/null
+++ b/node_modules/joi/dist/joi-browser.min.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.joi=t():e.joi=t()}(window,(function(){return function(e){var t={};function r(s){if(t[s])return t[s].exports;var n=t[s]={i:s,l:!1,exports:{}};return e[s].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,s){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(r.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(s,n,function(t){return e[t]}.bind(null,n));return s},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=11)}([function(e,t,r){"use strict";const s=r(12);e.exports=function(e,...t){if(!e){if(1===t.length&&t[0]instanceof Error)throw t[0];throw new s(t)}}},function(e,t,r){"use strict";const s=r(0),n=r(12),a=r(29);let o,i;const l={isoDate:/^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/};t.version=a.version,t.defaults={abortEarly:!0,allowUnknown:!1,artifacts:!1,cache:!0,context:null,convert:!0,dateFormat:"iso",errors:{escapeHtml:!1,label:"path",language:null,render:!0,stack:!1,wrap:{label:'"',array:"[]"}},externals:!0,messages:{},nonEnumerables:!1,noDefaults:!1,presence:"optional",skipFunctions:!1,stripUnknown:!1,warnings:!1},t.symbols={any:Symbol.for("@hapi/joi/schema"),arraySingle:Symbol("arraySingle"),deepDefault:Symbol("deepDefault"),errors:Symbol("errors"),literal:Symbol("literal"),override:Symbol("override"),parent:Symbol("parent"),prefs:Symbol("prefs"),ref:Symbol("ref"),template:Symbol("template"),values:Symbol("values")},t.assertOptions=function(e,t,r="Options"){s(e&&"object"==typeof e&&!Array.isArray(e),"Options must be of type object");const n=Object.keys(e).filter(e=>!t.includes(e));s(0===n.length,"".concat(r," contain unknown keys: ").concat(n))},t.checkPreferences=function(e){i=i||r(16);const t=i.preferences.validate(e);if(t.error)throw new n([t.error.details[0].message])},t.compare=function(e,t,r){switch(r){case"=":return e===t;case">":return e>t;case"<":return e<t;case">=":return e>=t;case"<=":return e<=t}},t.default=function(e,t){return void 0===e?t:e},t.isIsoDate=function(e){return l.isoDate.test(e)},t.isNumber=function(e){return"number"==typeof e&&!isNaN(e)},t.isResolvable=function(e){return!!e&&(e[t.symbols.ref]||e[t.symbols.template])},t.isSchema=function(e,r={}){const n=e&&e[t.symbols.any];return!!n&&(s(r.legacy||n.version===t.version,"Cannot mix different versions of joi schemas"),!0)},t.isValues=function(e){return e[t.symbols.values]},t.limit=function(e){return Number.isSafeInteger(e)&&e>=0},t.preferences=function(e,s){o=o||r(9),e=e||{},s=s||{};const n=Object.assign({},e,s);return s.errors&&e.errors&&(n.errors=Object.assign({},e.errors,s.errors),n.errors.wrap=Object.assign({},e.errors.wrap,s.errors.wrap)),s.messages&&(n.messages=o.compile(s.messages,e.messages)),delete n[t.symbols.prefs],n},t.tryWithPath=function(e,t,r={}){try{return e()}catch(e){throw void 0!==e.path?e.path=t+"."+e.path:e.path=t,r.append&&(e.message="".concat(e.message," (").concat(e.path,")")),e}},t.validateArg=function(e,r,{assert:s,message:n}){if(t.isSchema(s)){const t=s.validate(e);if(!t.error)return;return t.error.message}if(!s(e))return r?"".concat(r," ").concat(n):n},t.verifyFlat=function(e,t){for(const r of e)s(!Array.isArray(r),"Method no longer accepts array arguments:",t)}},function(e,t,r){"use strict";const s=r(6),n=r(13),a=r(14),o={needsProtoHack:new Set([n.set,n.map,n.weakSet,n.weakMap])};e.exports=o.clone=function(e,t={},r=null){if("object"!=typeof e||null===e)return e;let s=o.clone,i=r;if(t.shallow){if(!0!==t.shallow)return o.cloneWithShallow(e,t);s=e=>e}else if(i){const t=i.get(e);if(t)return t}else i=new Map;const l=n.getInternalProto(e);if(l===n.buffer)return!1;if(l===n.date)return new Date(e.getTime());if(l===n.regex)return new RegExp(e);const c=o.base(e,l,t);if(c===e)return e;if(i&&i.set(e,c),l===n.set)for(const r of e)c.add(s(r,t,i));else if(l===n.map)for(const[r,n]of e)c.set(r,s(n,t,i));const u=a.keys(e,t);for(const r of u){if("__proto__"===r)continue;if(l===n.array&&"length"===r){c.length=e.length;continue}const a=Object.getOwnPropertyDescriptor(e,r);a?a.get||a.set?Object.defineProperty(c,r,a):a.enumerable?c[r]=s(e[r],t,i):Object.defineProperty(c,r,{enumerable:!1,writable:!0,configurable:!0,value:s(e[r],t,i)}):Object.defineProperty(c,r,{enumerable:!0,writable:!0,configurable:!0,value:s(e[r],t,i)})}return c},o.cloneWithShallow=function(e,t){const r=t.shallow;(t=Object.assign({},t)).shallow=!1;const n=new Map;for(const t of r){const r=s(e,t);"object"!=typeof r&&"function"!=typeof r||n.set(r,r)}return o.clone(e,t,n)},o.base=function(e,t,r){if(!1===r.prototype)return o.needsProtoHack.has(t)?new t.constructor:t===n.array?[]:{};const s=Object.getPrototypeOf(e);if(s&&s.isImmutable)return e;if(t===n.array){const e=[];return s!==t&&Object.setPrototypeOf(e,s),e}if(o.needsProtoHack.has(t)){const e=new s.constructor;return s!==t&&Object.setPrototypeOf(e,s),e}return Object.create(s)}},function(e,t,r){"use strict";const s=r(0),n=r(34),a=r(1),o=r(9);e.exports=n.extend({type:"any",flags:{only:{default:!1}},terms:{alterations:{init:null},examples:{init:null},externals:{init:null},metas:{init:[]},notes:{init:[]},shared:{init:null},tags:{init:[]},whens:{init:null}},rules:{custom:{method(e,t){return s("function"==typeof e,"Method must be a function"),s(void 0===t||t&&"string"==typeof t,"Description must be a non-empty string"),this.$_addRule({name:"custom",args:{method:e,description:t}})},validate(e,t,{method:r}){try{return r(e,t)}catch(e){return t.error("any.custom",{error:e})}},args:["method","description"],multi:!0},messages:{method(e){return this.prefs({messages:e})}},shared:{method(e){s(a.isSchema(e)&&e._flags.id,"Schema must be a schema with an id");const t=this.clone();return t.$_terms.shared=t.$_terms.shared||[],t.$_terms.shared.push(e),t.$_mutateRegister(e),t}},warning:{method(e,t){return s(e&&"string"==typeof e,"Invalid warning code"),this.$_addRule({name:"warning",args:{code:e,local:t},warn:!0})},validate:(e,t,{code:r,local:s})=>t.error(r,s),args:["code","local"],multi:!0}},modifiers:{keep(e,t=!0){e.keep=t},message(e,t){e.message=o.compile(t)},warn(e,t=!0){e.warn=t}},manifest:{build(e,t){for(const r in t){const s=t[r];if(["examples","externals","metas","notes","tags"].includes(r))for(const t of s)e=e[r.slice(0,-1)](t);else if("alterations"!==r)if("whens"!==r){if("shared"===r)for(const t of s)e=e.shared(t)}else for(const t of s){const{ref:r,is:s,not:n,then:a,otherwise:o,concat:i}=t;e=i?e.concat(i):r?e.when(r,{is:s,not:n,then:a,otherwise:o,switch:t.switch,break:t.break}):e.when(s,{then:a,otherwise:o,break:t.break})}else{const t={};for(const{target:e,adjuster:r}of s)t[e]=r;e=e.alter(t)}}return e}},messages:{"any.custom":"{{#label}} failed custom validation because {{#error.message}}","any.default":"{{#label}} threw an error when running default method","any.failover":"{{#label}} threw an error when running failover method","any.invalid":"{{#label}} contains an invalid value","any.only":'{{#label}} must be {if(#valids.length == 1, "", "one of ")}{{#valids}}',"any.ref":"{{#label}} {{#arg}} references {{:#ref}} which {{#reason}}","any.required":"{{#label}} is required","any.unknown":"{{#label}} is not allowed"}})},function(e,t,r){"use strict";const s=r(32),n=r(1),a=r(7);t.Report=class{constructor(e,r,s,n,a,o,i){if(this.code=e,this.flags=n,this.messages=a,this.path=o.path,this.prefs=i,this.state=o,this.value=r,this.message=null,this.template=null,this.local=s||{},this.local.label=t.label(this.flags,this.state,this.prefs,this.messages),void 0===this.value||this.local.hasOwnProperty("value")||(this.local.value=this.value),this.path.length){const e=this.path[this.path.length-1];"object"!=typeof e&&(this.local.key=e)}}_setTemplate(e){if(this.template=e,!this.flags.label&&0===this.path.length){const e=this._template(this.template,"root");e&&(this.local.label=e)}}toString(){if(this.message)return this.message;const e=this.code;if(!this.prefs.errors.render)return this.code;const t=this._template(this.template)||this._template(this.prefs.messages)||this._template(this.messages);return void 0===t?'Error code "'.concat(e,'" is not defined, your custom type is missing the correct messages definition'):(this.message=t.render(this.value,this.state,this.prefs,this.local,{errors:this.prefs.errors,messages:[this.prefs.messages,this.messages]}),this.prefs.errors.label||(this.message=this.message.replace(/^"" /,"").trim()),this.message)}_template(e,r){return t.template(this.value,e,r||this.code,this.state,this.prefs)}},t.path=function(e){let t="";for(const r of e)"object"!=typeof r&&("string"==typeof r?(t&&(t+="."),t+=r):t+="[".concat(r,"]"));return t},t.template=function(e,t,r,s,o){if(!t)return;if(a.isTemplate(t))return"root"!==r?t:null;let i=o.errors.language;return n.isResolvable(i)&&(i=i.resolve(e,s,o)),i&&t[i]&&void 0!==t[i][r]?t[i][r]:t[r]},t.label=function(e,r,s,n){if(e.label)return e.label;if(!s.errors.label)return"";let a=r.path;"key"===s.errors.label&&r.path.length>1&&(a=r.path.slice(-1));const o=t.path(a);return o||(t.template(null,s.messages,"root",r,s)||n&&t.template(null,n,"root",r,s)||"value")},t.process=function(e,r,s){if(!e)return null;const{override:n,message:a,details:o}=t.details(e);if(n)return n;if(s.errors.stack)return new t.ValidationError(a,o,r);const i=Error.stackTraceLimit;Error.stackTraceLimit=0;const l=new t.ValidationError(a,o,r);return Error.stackTraceLimit=i,l},t.details=function(e,t={}){let r=[];const s=[];for(const n of e){if(n instanceof Error){if(!1!==t.override)return{override:n};const e=n.toString();r.push(e),s.push({message:e,type:"override",context:{error:n}});continue}const e=n.toString();r.push(e),s.push({message:e,path:n.path.filter(e=>"object"!=typeof e),type:n.code,context:n.local})}return r.length>1&&(r=[...new Set(r)]),{message:r.join(". "),details:s}},t.ValidationError=class extends Error{constructor(e,t,r){super(e),this._original=r,this.details=t}static isError(e){return e instanceof t.ValidationError}},t.ValidationError.prototype.isJoi=!0,t.ValidationError.prototype.name="ValidationError",t.ValidationError.prototype.annotate=s.error},function(e,t,r){"use strict";function s(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,s)}return r}function n(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?s(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):s(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const o=r(0),i=r(2),l=r(6),c=r(1);let u;const f={symbol:Symbol("ref"),defaults:{adjust:null,in:!1,iterables:null,map:null,separator:".",type:"value"}};t.create=function(e,t={}){o("string"==typeof e,"Invalid reference key:",e),c.assertOptions(t,["adjust","ancestor","in","iterables","map","prefix","render","separator"]),o(!t.prefix||"object"==typeof t.prefix,"options.prefix must be of type object");const r=Object.assign({},f.defaults,t);delete r.prefix;const s=r.separator,n=f.context(e,s,t.prefix);if(r.type=n.type,e=n.key,"value"===r.type)if(n.root&&(o(!s||e[0]!==s,"Cannot specify relative path with root prefix"),r.ancestor="root",e||(e=null)),s&&s===e)e=null,r.ancestor=0;else if(void 0!==r.ancestor)o(!s||!e||e[0]!==s,"Cannot combine prefix with ancestor option");else{const[t,n]=f.ancestor(e,s);n&&""===(e=e.slice(n))&&(e=null),r.ancestor=t}return r.path=s?null===e?[]:e.split(s):[e],new f.Ref(r)},t.in=function(e,r={}){return t.create(e,n(n({},r),{},{in:!0}))},t.isRef=function(e){return!!e&&!!e[c.symbols.ref]},f.Ref=class{constructor(e){o("object"==typeof e,"Invalid reference construction"),c.assertOptions(e,["adjust","ancestor","in","iterables","map","path","render","separator","type","depth","key","root","display"]),o([!1,void 0].includes(e.separator)||"string"==typeof e.separator&&1===e.separator.length,"Invalid separator"),o(!e.adjust||"function"==typeof e.adjust,"options.adjust must be a function"),o(!e.map||Array.isArray(e.map),"options.map must be an array"),o(!e.map||!e.adjust,"Cannot set both map and adjust options"),Object.assign(this,f.defaults,e),o("value"===this.type||void 0===this.ancestor,"Non-value references cannot reference ancestors"),Array.isArray(this.map)&&(this.map=new Map(this.map)),this.depth=this.path.length,this.key=this.path.length?this.path.join(this.separator):null,this.root=this.path[0],this.updateDisplay()}resolve(e,t,r,s,n={}){return o(!this.in||n.in,"Invalid in() reference usage"),"global"===this.type?this._resolve(r.context,t,n):"local"===this.type?this._resolve(s,t,n):this.ancestor?"root"===this.ancestor?this._resolve(t.ancestors[t.ancestors.length-1],t,n):(o(this.ancestor<=t.ancestors.length,"Invalid reference exceeds the schema root:",this.display),this._resolve(t.ancestors[this.ancestor-1],t,n)):this._resolve(e,t,n)}_resolve(e,t,r){let s;if("value"===this.type&&t.mainstay.shadow&&!1!==r.shadow&&(s=t.mainstay.shadow.get(this.absolute(t))),void 0===s&&(s=l(e,this.path,{iterables:this.iterables,functions:!0})),this.adjust&&(s=this.adjust(s)),this.map){const e=this.map.get(s);void 0!==e&&(s=e)}return t.mainstay&&t.mainstay.tracer.resolve(t,this,s),s}toString(){return this.display}absolute(e){return[...e.path.slice(0,-this.ancestor),...this.path]}clone(){return new f.Ref(this)}describe(){const e={path:this.path};"value"!==this.type&&(e.type=this.type),"."!==this.separator&&(e.separator=this.separator),"value"===this.type&&1!==this.ancestor&&(e.ancestor=this.ancestor),this.map&&(e.map=[...this.map]);for(const t of["adjust","iterables","render"])null!==this[t]&&void 0!==this[t]&&(e[t]=this[t]);return!1!==this.in&&(e.in=!0),{ref:e}}updateDisplay(){const e=null!==this.key?this.key:"";if("value"!==this.type)return void(this.display="ref:".concat(this.type,":").concat(e));if(!this.separator)return void(this.display="ref:".concat(e));if(!this.ancestor)return void(this.display="ref:".concat(this.separator).concat(e));if("root"===this.ancestor)return void(this.display="ref:root:".concat(e));if(1===this.ancestor)return void(this.display="ref:".concat(e||".."));const t=new Array(this.ancestor+1).fill(this.separator).join("");this.display="ref:".concat(t).concat(e||"")}},f.Ref.prototype[c.symbols.ref]=!0,t.build=function(e){return"value"===(e=Object.assign({},f.defaults,e)).type&&void 0===e.ancestor&&(e.ancestor=1),new f.Ref(e)},f.context=function(e,t,r={}){if(e=e.trim(),r){const s=void 0===r.global?"$":r.global;if(s!==t&&e.startsWith(s))return{key:e.slice(s.length),type:"global"};const n=void 0===r.local?"#":r.local;if(n!==t&&e.startsWith(n))return{key:e.slice(n.length),type:"local"};const a=void 0===r.root?"/":r.root;if(a!==t&&e.startsWith(a))return{key:e.slice(a.length),type:"value",root:!0}}return{key:e,type:"value"}},f.ancestor=function(e,t){if(!t)return[1,0];if(e[0]!==t)return[1,0];if(e[1]!==t)return[0,1];let r=2;for(;e[r]===t;)++r;return[r-1,r]},t.toSibling=0,t.toParent=1,t.Manager=class{constructor(){this.refs=[]}register(e,s){if(e)if(s=void 0===s?t.toParent:s,Array.isArray(e))for(const t of e)this.register(t,s);else if(c.isSchema(e))for(const t of e._refs.refs)t.ancestor-s>=0&&this.refs.push({ancestor:t.ancestor-s,root:t.root});else t.isRef(e)&&"value"===e.type&&e.ancestor-s>=0&&this.refs.push({ancestor:e.ancestor-s,root:e.root}),u=u||r(7),u.isTemplate(e)&&this.register(e.refs(),s)}get length(){return this.refs.length}clone(){const e=new t.Manager;return e.refs=i(this.refs),e}reset(){this.refs=[]}roots(){return this.refs.filter(e=>!e.ancestor).map(e=>e.root)}}},function(e,t,r){"use strict";const s=r(0),n={};e.exports=function(e,t,r){if(!1===t||null==t)return e;"string"==typeof(r=r||{})&&(r={separator:r});const a=Array.isArray(t);s(!a||!r.separator,"Separator option no valid for array-based chain");const o=a?t:t.split(r.separator||".");let i=e;for(let e=0;e<o.length;++e){let a=o[e];const l=r.iterables&&n.iterables(i);if(Array.isArray(i)||"set"===l){const e=Number(a);Number.isInteger(e)&&(a=e<0?i.length+e:e)}if(!i||"function"==typeof i&&!1===r.functions||!l&&void 0===i[a]){s(!r.strict||e+1===o.length,"Missing segment",a,"in reach path ",t),s("object"==typeof i||!0===r.functions||"function"!=typeof i,"Invalid segment",a,"in reach path ",t),i=r.default;break}i=l?"set"===l?[...i][a]:i.get(a):i[a]}return i},n.iterables=function(e){return e instanceof Set?"set":e instanceof Map?"map":void 0}},function(e,t,r){"use strict";function s(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,s)}return r}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const a=r(0),o=r(2),i=r(30),l=r(31),c=r(1),u=r(4),f=r(5),m={symbol:Symbol("template"),opens:new Array(1e3).join("\0"),closes:new Array(1e3).join(""),dateFormat:{date:Date.prototype.toDateString,iso:Date.prototype.toISOString,string:Date.prototype.toString,time:Date.prototype.toTimeString,utc:Date.prototype.toUTCString}};e.exports=m.Template=class{constructor(e,t){a("string"==typeof e,"Template source must be a string"),a(!e.includes("\0")&&!e.includes(""),"Template source cannot contain reserved control characters"),this.source=e,this.rendered=e,this._template=null,this._settings=o(t),this._parse()}_parse(){if(!this.source.includes("{"))return;const e=m.encode(this.source),t=m.split(e);let r=!1;const s=[],n=t.shift();n&&s.push(n);for(const e of t){const t="{"!==e[0],n=t?"}":"}}",a=e.indexOf(n);if(-1===a||"{"===e[1]){s.push("{".concat(m.decode(e)));continue}let o=e.slice(t?0:1,a);const i=":"===o[0];i&&(o=o.slice(1));const l=this._ref(m.decode(o),{raw:t,wrapped:i});s.push(l),"string"!=typeof l&&(r=!0);const c=e.slice(a+n.length);c&&s.push(m.decode(c))}r?this._template=s:this.rendered=s.join("")}static date(e,t){return m.dateFormat[t.dateFormat].call(e)}describe(e={}){if(!this._settings&&e.compact)return this.source;const t={template:this.source};return this._settings&&(t.options=this._settings),t}static build(e){return new m.Template(e.template,e.options)}isDynamic(){return!!this._template}static isTemplate(e){return!!e&&!!e[c.symbols.template]}refs(){if(!this._template)return;const e=[];for(const t of this._template)"string"!=typeof t&&e.push(...t.refs);return e}resolve(e,t,r,s){return this._template&&1===this._template.length?this._part(this._template[0],e,t,r,s,{}):this.render(e,t,r,s)}_part(e,...t){return e.ref?e.ref.resolve(...t):e.formula.evaluate(t)}render(e,t,r,s,n={}){if(!this.isDynamic())return this.rendered;const a=[];for(const o of this._template)if("string"==typeof o)a.push(o);else{const l=this._part(o,e,t,r,s,n),c=m.stringify(l,e,t,r,s,n);if(void 0!==c){const e=o.raw||!1===(n.errors&&n.errors.escapeHtml)?c:i(c);a.push(m.wrap(e,o.wrapped&&r.errors.wrap.label))}}return a.join("")}_ref(e,{raw:t,wrapped:r}){const s=[],n=e=>{const t=f.create(e,this._settings);return s.push(t),e=>t.resolve(...e)};try{var a=new l.Parser(e,{reference:n,functions:m.functions,constants:m.constants})}catch(t){throw t.message='Invalid template variable "'.concat(e,'" fails due to: ').concat(t.message),t}if(a.single){if("reference"===a.single.type){const e=s[0];return{ref:e,raw:t,refs:s,wrapped:r||"local"===e.type&&"label"===e.key}}return m.stringify(a.single.value)}return{formula:a,raw:t,refs:s}}toString(){return this.source}},m.Template.prototype[c.symbols.template]=!0,m.Template.prototype.isImmutable=!0,m.encode=function(e){return e.replace(/\\(\{+)/g,(e,t)=>m.opens.slice(0,t.length)).replace(/\\(\}+)/g,(e,t)=>m.closes.slice(0,t.length))},m.decode=function(e){return e.replace(/\u0000/g,"{").replace(/\u0001/g,"}")},m.split=function(e){const t=[];let r="";for(let s=0;s<e.length;++s){const n=e[s];if("{"===n){let n="";for(;s+1<e.length&&"{"===e[s+1];)n+="{",++s;t.push(r),r=n}else r+=n}return t.push(r),t},m.wrap=function(e,t){return t?1===t.length?"".concat(t).concat(e).concat(t):"".concat(t[0]).concat(e).concat(t[1]):e},m.stringify=function(e,t,r,a,o,i){const l=typeof e;let c=!1;if(f.isRef(e)&&e.render&&(c=e.in,e=e.resolve(t,r,a,o,function(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?s(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):s(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}({in:e.in},i))),null===e)return"null";if("string"===l)return e;if("number"===l||"function"===l||"symbol"===l)return e.toString();if("object"!==l)return JSON.stringify(e);if(e instanceof Date)return m.Template.date(e,a);if(e instanceof Map){const t=[];for(const[r,s]of e.entries())t.push("".concat(r.toString()," -> ").concat(s.toString()));e=t}if(!Array.isArray(e))return e.toString();let u="";for(const s of e)u=u+(u.length?", ":"")+m.stringify(s,t,r,a,o,i);return c?u:m.wrap(u,a.errors.wrap.array)},m.constants={true:!0,false:!1,null:null,second:1e3,minute:6e4,hour:36e5,day:864e5},m.functions={if:(e,t,r)=>e?t:r,msg(e){const[t,r,s,n,a]=this,o=a.messages;if(!o)return"";const i=u.template(t,o[0],e,r,s)||u.template(t,o[1],e,r,s);return i?i.render(t,r,s,n,a):""},number:e=>"number"==typeof e?e:"string"==typeof e?parseFloat(e):"boolean"==typeof e?e?1:0:e instanceof Date?e.getTime():null}},function(e,t,r){"use strict";const s=r(0),n=r(1),a=r(5),o={};t.schema=function(e,t,r={}){n.assertOptions(r,["appendPath","override"]);try{return o.schema(e,t,r)}catch(e){throw r.appendPath&&void 0!==e.path&&(e.message="".concat(e.message," (").concat(e.path,")")),e}},o.schema=function(e,t,r){s(void 0!==t,"Invalid undefined schema"),Array.isArray(t)&&(s(t.length,"Invalid empty array schema"),1===t.length&&(t=t[0]));const a=(t,...s)=>!1!==r.override?t.valid(e.override,...s):t.valid(...s);if(o.simple(t))return a(e,t);if("function"==typeof t)return e.custom(t);if(s("object"==typeof t,"Invalid schema content:",typeof t),n.isResolvable(t))return a(e,t);if(n.isSchema(t))return t;if(Array.isArray(t)){for(const r of t)if(!o.simple(r))return e.alternatives().try(...t);return a(e,...t)}return t instanceof RegExp?e.string().regex(t):t instanceof Date?a(e.date(),t):(s(Object.getPrototypeOf(t)===Object.getPrototypeOf({}),"Schema can only contain plain objects"),e.object().keys(t))},t.ref=function(e,t){return a.isRef(e)?e:a.create(e,t)},t.compile=function(e,r,a={}){n.assertOptions(a,["legacy"]);const i=r&&r[n.symbols.any];if(i)return s(a.legacy||i.version===n.version,"Cannot mix different versions of joi schemas:",i.version,n.version),r;if("object"!=typeof r||!a.legacy)return t.schema(e,r,{appendPath:!0});const l=o.walk(r);return l?l.compile(l.root,r):t.schema(e,r,{appendPath:!0})},o.walk=function(e){if("object"!=typeof e)return null;if(Array.isArray(e)){for(const t of e){const e=o.walk(t);if(e)return e}return null}const t=e[n.symbols.any];if(t)return{root:e[t.root],compile:t.compile};s(Object.getPrototypeOf(e)===Object.getPrototypeOf({}),"Schema can only contain plain objects");for(const t in e){const r=o.walk(e[t]);if(r)return r}return null},o.simple=function(e){return null===e||["boolean","string","number"].includes(typeof e)},t.when=function(e,r,i){if(void 0===i&&(s(r&&"object"==typeof r,"Missing options"),i=r,r=a.create(".")),Array.isArray(i)&&(i={switch:i}),n.assertOptions(i,["is","not","then","otherwise","switch","break"]),n.isSchema(r))return s(void 0===i.is,'"is" can not be used with a schema condition'),s(void 0===i.not,'"not" can not be used with a schema condition'),s(void 0===i.switch,'"switch" can not be used with a schema condition'),o.condition(e,{is:r,then:i.then,otherwise:i.otherwise,break:i.break});if(s(a.isRef(r)||"string"==typeof r,"Invalid condition:",r),s(void 0===i.not||void 0===i.is,'Cannot combine "is" with "not"'),void 0===i.switch){let l=i;void 0!==i.not&&(l={is:i.not,then:i.otherwise,otherwise:i.then,break:i.break});let c=void 0!==l.is?e.$_compile(l.is):e.$_root.invalid(null,!1,0,"").required();return s(void 0!==l.then||void 0!==l.otherwise,'options must have at least one of "then", "otherwise", or "switch"'),s(void 0===l.break||void 0===l.then||void 0===l.otherwise,"Cannot specify then, otherwise, and break all together"),void 0===i.is||a.isRef(i.is)||n.isSchema(i.is)||(c=c.required()),o.condition(e,{ref:t.ref(r),is:c,then:l.then,otherwise:l.otherwise,break:l.break})}s(Array.isArray(i.switch),'"switch" must be an array'),s(void 0===i.is,'Cannot combine "switch" with "is"'),s(void 0===i.not,'Cannot combine "switch" with "not"'),s(void 0===i.then,'Cannot combine "switch" with "then"');const l={ref:t.ref(r),switch:[],break:i.break};for(let t=0;t<i.switch.length;++t){const r=i.switch[t],o=t===i.switch.length-1;n.assertOptions(r,o?["is","then","otherwise"]:["is","then"]),s(void 0!==r.is,'Switch statement missing "is"'),s(void 0!==r.then,'Switch statement missing "then"');const c={is:e.$_compile(r.is),then:e.$_compile(r.then)};if(a.isRef(r.is)||n.isSchema(r.is)||(c.is=c.is.required()),o){s(void 0===i.otherwise||void 0===r.otherwise,'Cannot specify "otherwise" inside and outside a "switch"');const t=void 0!==i.otherwise?i.otherwise:r.otherwise;void 0!==t&&(s(void 0===l.break,"Cannot specify both otherwise and break"),c.otherwise=e.$_compile(t))}l.switch.push(c)}return l},o.condition=function(e,t){for(const r of["then","otherwise"])void 0===t[r]?delete t[r]:t[r]=e.$_compile(t[r]);return t}},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(7);t.compile=function(e,t){if("string"==typeof e)return s(!t,"Cannot set single message string"),new a(e);if(a.isTemplate(e))return s(!t,"Cannot set single message template"),e;s("object"==typeof e&&!Array.isArray(e),"Invalid message options"),t=t?n(t):{};for(let r in e){const n=e[r];if("root"===r||a.isTemplate(n)){t[r]=n;continue}if("string"==typeof n){t[r]=new a(n);continue}s("object"==typeof n&&!Array.isArray(n),"Invalid message for",r);const o=r;for(r in t[o]=t[o]||{},n){const e=n[r];"root"===r||a.isTemplate(e)?t[o][r]=e:(s("string"==typeof e,"Invalid message for",r,"in",o),t[o][r]=new a(e))}}return t},t.decompile=function(e){const t={};for(let r in e){const s=e[r];if("root"===r){t[r]=s;continue}if(a.isTemplate(s)){t[r]=s.describe({compact:!0});continue}const n=r;for(r in t[n]={},s){const e=s[r];"root"!==r?t[n][r]=e.describe({compact:!0}):t[n][r]=e}}return t},t.merge=function(e,r){if(!e)return t.compile(r);if(!r)return e;if("string"==typeof r)return new a(r);if(a.isTemplate(r))return r;const o=n(e);for(let e in r){const t=r[e];if("root"===e||a.isTemplate(t)){o[e]=t;continue}if("string"==typeof t){o[e]=new a(t);continue}s("object"==typeof t&&!Array.isArray(t),"Invalid message for",e);const n=e;for(e in o[n]=o[n]||{},t){const r=t[e];"root"===e||a.isTemplate(r)?o[n][e]=r:(s("string"==typeof r,"Invalid message for",e,"in",n),o[n][e]=new a(r))}}return o}},function(e,t,r){"use strict";const s=r(13),n={mismatched:null};e.exports=function(e,t,r){return r=Object.assign({prototype:!0},r),!!n.isDeepEqual(e,t,r,[])},n.isDeepEqual=function(e,t,r,a){if(e===t)return 0!==e||1/e==1/t;const o=typeof e;if(o!==typeof t)return!1;if(null===e||null===t)return!1;if("function"===o){if(!r.deepFunction||e.toString()!==t.toString())return!1}else if("object"!==o)return e!=e&&t!=t;const i=n.getSharedType(e,t,!!r.prototype);switch(i){case s.buffer:return!1;case s.promise:return e===t;case s.regex:return e.toString()===t.toString();case n.mismatched:return!1}for(let r=a.length-1;r>=0;--r)if(a[r].isSame(e,t))return!0;a.push(new n.SeenEntry(e,t));try{return!!n.isDeepEqualObj(i,e,t,r,a)}finally{a.pop()}},n.getSharedType=function(e,t,r){if(r)return Object.getPrototypeOf(e)!==Object.getPrototypeOf(t)?n.mismatched:s.getInternalProto(e);const a=s.getInternalProto(e);return a!==s.getInternalProto(t)?n.mismatched:a},n.valueOf=function(e){const t=e.valueOf;if(void 0===t)return e;try{return t.call(e)}catch(e){return e}},n.hasOwnEnumerableProperty=function(e,t){return Object.prototype.propertyIsEnumerable.call(e,t)},n.isSetSimpleEqual=function(e,t){for(const r of Set.prototype.values.call(e))if(!Set.prototype.has.call(t,r))return!1;return!0},n.isDeepEqualObj=function(e,t,r,a,o){const{isDeepEqual:i,valueOf:l,hasOwnEnumerableProperty:c}=n,{keys:u,getOwnPropertySymbols:f}=Object;if(e===s.array){if(!a.part){if(t.length!==r.length)return!1;for(let e=0;e<t.length;++e)if(!i(t[e],r[e],a,o))return!1;return!0}for(const e of t)for(const t of r)if(i(e,t,a,o))return!0}else if(e===s.set){if(t.size!==r.size)return!1;if(!n.isSetSimpleEqual(t,r)){const e=new Set(Set.prototype.values.call(r));for(const r of Set.prototype.values.call(t)){if(e.delete(r))continue;let t=!1;for(const s of e)if(i(r,s,a,o)){e.delete(s),t=!0;break}if(!t)return!1}}}else if(e===s.map){if(t.size!==r.size)return!1;for(const[e,s]of Map.prototype.entries.call(t)){if(void 0===s&&!Map.prototype.has.call(r,e))return!1;if(!i(s,Map.prototype.get.call(r,e),a,o))return!1}}else if(e===s.error&&(t.name!==r.name||t.message!==r.message))return!1;const m=l(t),h=l(r);if((t!==m||r!==h)&&!i(m,h,a,o))return!1;const p=u(t);if(!a.part&&p.length!==u(r).length&&!a.skip)return!1;let d=0;for(const e of p)if(a.skip&&a.skip.includes(e))void 0===r[e]&&++d;else{if(!c(r,e))return!1;if(!i(t[e],r[e],a,o))return!1}if(!a.part&&p.length-d!==u(r).length)return!1;if(!1!==a.symbols){const e=f(t),s=new Set(f(r));for(const n of e){if(!a.skip||!a.skip.includes(n))if(c(t,n)){if(!c(r,n))return!1;if(!i(t[n],r[n],a,o))return!1}else if(c(r,n))return!1;s.delete(n)}for(const e of s)if(c(r,e))return!1}return!0},n.SeenEntry=class{constructor(e,t){this.obj=e,this.ref=t}isSame(e,t){return this.obj===e&&this.ref===t}}},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(15),o=r(1),i=r(8),l=r(4),c=r(17),u=r(18),f=r(5),m=r(7),h=r(19);let p;const d={types:{alternatives:r(33),any:r(3),array:r(39),boolean:r(40),date:r(41),function:r(42),link:r(45),number:r(46),object:r(47),string:r(48),symbol:r(52)},aliases:{alt:"alternatives",bool:"boolean",func:"function"}};d.root=function(){const e={_types:new Set(Object.keys(d.types))};for(const t of e._types)e[t]=function(...e){return s(!e.length||["alternatives","link","object"].includes(t),"The",t,"type does not allow arguments"),d.generate(this,d.types[t],e)};for(const t of["allow","custom","disallow","equal","exist","forbidden","invalid","not","only","optional","options","prefs","preferences","required","strip","valid","when"])e[t]=function(...e){return this.any()[t](...e)};Object.assign(e,d.methods);for(const t in d.aliases){const r=d.aliases[t];e[t]=e[r]}return e.x=e.expression,h.setup&&h.setup(e),e},d.methods={ValidationError:l.ValidationError,version:o.version,cache:a.provider,assert(e,t,...r){d.assert(e,t,!0,r)},attempt:(e,t,...r)=>d.assert(e,t,!1,r),build(e){return s("function"==typeof u.build,"Manifest functionality disabled"),u.build(this,e)},checkPreferences(e){o.checkPreferences(e)},compile(e,t){return i.compile(this,e,t)},defaults(e){s("function"==typeof e,"modifier must be a function");const t=Object.assign({},this);for(const r of t._types){const n=e(t[r]());s(o.isSchema(n),"modifier must return a valid schema object"),t[r]=function(...e){return d.generate(this,n,e)}}return t},expression:(...e)=>new m(...e),extend(...e){o.verifyFlat(e,"extend"),p=p||r(16),s(e.length,"You need to provide at least one extension"),this.assert(e,p.extensions);const t=Object.assign({},this);t._types=new Set(t._types);for(let r of e){"function"==typeof r&&(r=r(t)),this.assert(r,p.extension);const e=d.expandExtension(r,t);for(const r of e){s(void 0===t[r.type]||t._types.has(r.type),"Cannot override name",r.type);const e=r.base||this.any(),n=c.type(e,r);t._types.add(r.type),t[r.type]=function(...e){return d.generate(this,n,e)}}}return t},isError:l.ValidationError.isError,isExpression:m.isTemplate,isRef:f.isRef,isSchema:o.isSchema,in:(...e)=>f.in(...e),override:o.symbols.override,ref:(...e)=>f.create(...e),types(){const e={};for(const t of this._types)e[t]=this[t]();for(const t in d.aliases)e[t]=this[t]();return e}},d.assert=function(e,t,r,s){const a=s[0]instanceof Error||"string"==typeof s[0]?s[0]:null,i=a?s[1]:s[0],c=t.validate(e,o.preferences({errors:{stack:!0}},i||{}));let u=c.error;if(!u)return c.value;if(a instanceof Error)throw a;const f=r&&"function"==typeof u.annotate?u.annotate():u.message;throw u instanceof l.ValidationError==!1&&(u=n(u)),u.message=a?"".concat(a," ").concat(f):f,u},d.generate=function(e,t,r){return s(e,"Must be invoked on a Joi instance."),t.$_root=e,t._definition.args&&r.length?t._definition.args(t,...r):t},d.expandExtension=function(e,t){if("string"==typeof e.type)return[e];const r=[];for(const s of t._types)if(e.type.test(s)){const n=Object.assign({},e);n.type=s,n.base=t[s](),r.push(n)}return r},e.exports=d.root()},function(e,t,r){"use strict";const s=r(28);e.exports=class extends Error{constructor(e){super(e.filter(e=>""!==e).map(e=>"string"==typeof e?e:e instanceof Error?e.message:s(e)).join(" ")||"Unknown error"),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,t.assert)}}},function(e,t,r){"use strict";const s={};t=e.exports={array:Array.prototype,buffer:!1,date:Date.prototype,error:Error.prototype,generic:Object.prototype,map:Map.prototype,promise:Promise.prototype,regex:RegExp.prototype,set:Set.prototype,weakMap:WeakMap.prototype,weakSet:WeakSet.prototype},s.typeMap=new Map([["[object Error]",t.error],["[object Map]",t.map],["[object Promise]",t.promise],["[object Set]",t.set],["[object WeakMap]",t.weakMap],["[object WeakSet]",t.weakSet]]),t.getInternalProto=function(e){if(Array.isArray(e))return t.array;if(e instanceof Date)return t.date;if(e instanceof RegExp)return t.regex;if(e instanceof Error)return t.error;const r=Object.prototype.toString.call(e);return s.typeMap.get(r)||t.generic}},function(e,t,r){"use strict";t.keys=function(e,t={}){return!1!==t.symbols?Reflect.ownKeys(e):Object.getOwnPropertyNames(e)}},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(1),o={max:1e3,supported:new Set(["undefined","boolean","number","string"])};t.provider={provision:e=>new o.Cache(e)},o.Cache=class{constructor(e={}){a.assertOptions(e,["max"]),s(void 0===e.max||e.max&&e.max>0&&isFinite(e.max),"Invalid max cache size"),this._max=e.max||o.max,this._map=new Map,this._list=new o.List}get length(){return this._map.size}set(e,t){if(null!==e&&!o.supported.has(typeof e))return;let r=this._map.get(e);if(r)return r.value=t,void this._list.first(r);r=this._list.unshift({key:e,value:t}),this._map.set(e,r),this._compact()}get(e){const t=this._map.get(e);if(t)return this._list.first(t),n(t.value)}_compact(){if(this._map.size>this._max){const e=this._list.pop();this._map.delete(e.key)}}},o.List=class{constructor(){this.tail=null,this.head=null}unshift(e){return e.next=null,e.prev=this.head,this.head&&(this.head.next=e),this.head=e,this.tail||(this.tail=e),e}first(e){e!==this.head&&(this._remove(e),this.unshift(e))}pop(){return this._remove(this.tail)}_remove(e){const{next:t,prev:r}=e;return t.prev=r,r&&(r.next=t),e===this.tail&&(this.tail=t),e.prev=null,e.next=null,e}}},function(e,t,r){"use strict";const s=r(11),n={};n.wrap=s.string().min(1).max(2).allow(!1),t.preferences=s.object({allowUnknown:s.boolean(),abortEarly:s.boolean(),artifacts:s.boolean(),cache:s.boolean(),context:s.object(),convert:s.boolean(),dateFormat:s.valid("date","iso","string","time","utc"),debug:s.boolean(),errors:{escapeHtml:s.boolean(),label:s.valid("path","key",!1),language:[s.string(),s.object().ref()],render:s.boolean(),stack:s.boolean(),wrap:{label:n.wrap,array:n.wrap}},externals:s.boolean(),messages:s.object(),noDefaults:s.boolean(),nonEnumerables:s.boolean(),presence:s.valid("required","optional","forbidden"),skipFunctions:s.boolean(),stripUnknown:s.object({arrays:s.boolean(),objects:s.boolean()}).or("arrays","objects").allow(!0,!1),warnings:s.boolean()}).strict(),n.nameRx=/^[a-zA-Z0-9]\w*$/,n.rule=s.object({alias:s.array().items(s.string().pattern(n.nameRx)).single(),args:s.array().items(s.string(),s.object({name:s.string().pattern(n.nameRx).required(),ref:s.boolean(),assert:s.alternatives([s.function(),s.object().schema()]).conditional("ref",{is:!0,then:s.required()}),normalize:s.function(),message:s.string().when("assert",{is:s.function(),then:s.required()})})),convert:s.boolean(),manifest:s.boolean(),method:s.function().allow(!1),multi:s.boolean(),validate:s.function()}),t.extension=s.object({type:s.alternatives([s.string(),s.object().regex()]).required(),args:s.function(),cast:s.object().pattern(n.nameRx,s.object({from:s.function().maxArity(1).required(),to:s.function().minArity(1).maxArity(2).required()})),base:s.object().schema().when("type",{is:s.object().regex(),then:s.forbidden()}),coerce:[s.function().maxArity(3),s.object({method:s.function().maxArity(3).required(),from:s.array().items(s.string()).single()})],flags:s.object().pattern(n.nameRx,s.object({setter:s.string(),default:s.any()})),manifest:{build:s.function().arity(2)},messages:[s.object(),s.string()],modifiers:s.object().pattern(n.nameRx,s.function().minArity(1).maxArity(2)),overrides:s.object().pattern(n.nameRx,s.function()),prepare:s.function().maxArity(3),rebuild:s.function().arity(1),rules:s.object().pattern(n.nameRx,n.rule),terms:s.object().pattern(n.nameRx,s.object({init:s.array().allow(null).required(),manifest:s.object().pattern(/.+/,[s.valid("schema","single"),s.object({mapped:s.object({from:s.string().required(),to:s.string().required()}).required()})])})),validate:s.function().maxArity(3)}).strict(),t.extensions=s.array().items(s.object(),s.function().arity(1)).strict(),n.desc={buffer:s.object({buffer:s.string()}),func:s.object({function:s.function().required(),options:{literal:!0}}),override:s.object({override:!0}),ref:s.object({ref:s.object({type:s.valid("value","global","local"),path:s.array().required(),separator:s.string().length(1).allow(!1),ancestor:s.number().min(0).integer().allow("root"),map:s.array().items(s.array().length(2)).min(1),adjust:s.function(),iterables:s.boolean(),in:s.boolean(),render:s.boolean()}).required()}),regex:s.object({regex:s.string().min(3)}),special:s.object({special:s.valid("deep").required()}),template:s.object({template:s.string().required(),options:s.object()}),value:s.object({value:s.alternatives([s.object(),s.array()]).required()})},n.desc.entity=s.alternatives([s.array().items(s.link("...")),s.boolean(),s.function(),s.number(),s.string(),n.desc.buffer,n.desc.func,n.desc.ref,n.desc.regex,n.desc.special,n.desc.template,n.desc.value,s.link("/")]),n.desc.values=s.array().items(null,s.boolean(),s.function(),s.number().allow(1/0,-1/0),s.string().allow(""),s.symbol(),n.desc.buffer,n.desc.func,n.desc.override,n.desc.ref,n.desc.regex,n.desc.template,n.desc.value),n.desc.messages=s.object().pattern(/.+/,[s.string(),n.desc.template,s.object().pattern(/.+/,[s.string(),n.desc.template])]),t.description=s.object({type:s.string().required(),flags:s.object({cast:s.string(),default:s.any(),description:s.string(),empty:s.link("/"),failover:n.desc.entity,id:s.string(),label:s.string(),only:!0,presence:["optional","required","forbidden"],result:["raw","strip"],strip:s.boolean(),unit:s.string()}).unknown(),preferences:{allowUnknown:s.boolean(),abortEarly:s.boolean(),artifacts:s.boolean(),cache:s.boolean(),convert:s.boolean(),dateFormat:["date","iso","string","time","utc"],errors:{escapeHtml:s.boolean(),label:["path","key"],language:[s.string(),n.desc.ref],wrap:{label:n.wrap,array:n.wrap}},externals:s.boolean(),messages:n.desc.messages,noDefaults:s.boolean(),nonEnumerables:s.boolean(),presence:["required","optional","forbidden"],skipFunctions:s.boolean(),stripUnknown:s.object({arrays:s.boolean(),objects:s.boolean()}).or("arrays","objects").allow(!0,!1),warnings:s.boolean()},allow:n.desc.values,invalid:n.desc.values,rules:s.array().min(1).items({name:s.string().required(),args:s.object().min(1),keep:s.boolean(),message:[s.string(),n.desc.messages],warn:s.boolean()}),keys:s.object().pattern(/.*/,s.link("/")),link:n.desc.ref}).pattern(/^[a-z]\w*$/,s.any())},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(1),o=r(9),i={};t.type=function(e,t){const r=Object.getPrototypeOf(e),l=n(r),c=e._assign(Object.create(l)),u=Object.assign({},t);delete u.base,l._definition=u;const f=r._definition||{};u.messages=o.merge(f.messages,u.messages),u.properties=Object.assign({},f.properties,u.properties),c.type=u.type,u.flags=Object.assign({},f.flags,u.flags);const m=Object.assign({},f.terms);if(u.terms)for(const e in u.terms){const t=u.terms[e];s(void 0===c.$_terms[e],"Invalid term override for",u.type,e),c.$_terms[e]=t.init,m[e]=t}u.terms=m,u.args||(u.args=f.args),u.prepare=i.prepare(u.prepare,f.prepare),u.coerce&&("function"==typeof u.coerce&&(u.coerce={method:u.coerce}),u.coerce.from&&!Array.isArray(u.coerce.from)&&(u.coerce={method:u.coerce.method,from:[].concat(u.coerce.from)})),u.coerce=i.coerce(u.coerce,f.coerce),u.validate=i.validate(u.validate,f.validate);const h=Object.assign({},f.rules);if(u.rules)for(const e in u.rules){const t=u.rules[e];s("object"==typeof t,"Invalid rule definition for",u.type,e);let r=t.method;if(void 0===r&&(r=function(){return this.$_addRule(e)}),r&&(s(!l[e],"Rule conflict in",u.type,e),l[e]=r),s(!h[e],"Rule conflict in",u.type,e),h[e]=t,t.alias){const e=[].concat(t.alias);for(const r of e)l[r]=t.method}t.args&&(t.argsByName=new Map,t.args=t.args.map(e=>("string"==typeof e&&(e={name:e}),s(!t.argsByName.has(e.name),"Duplicated argument name",e.name),a.isSchema(e.assert)&&(e.assert=e.assert.strict().label(e.name)),t.argsByName.set(e.name,e),e)))}u.rules=h;const p=Object.assign({},f.modifiers);if(u.modifiers)for(const e in u.modifiers){s(!l[e],"Rule conflict in",u.type,e);const t=u.modifiers[e];s("function"==typeof t,"Invalid modifier definition for",u.type,e);const r=function(t){return this.rule({[e]:t})};l[e]=r,p[e]=t}if(u.modifiers=p,u.overrides){l._super=r,c.$_super={};for(const e in u.overrides)s(r[e],"Cannot override missing",e),u.overrides[e][a.symbols.parent]=r[e],c.$_super[e]=r[e].bind(c);Object.assign(l,u.overrides)}u.cast=Object.assign({},f.cast,u.cast);const d=Object.assign({},f.manifest,u.manifest);return d.build=i.build(u.manifest&&u.manifest.build,f.manifest&&f.manifest.build),u.manifest=d,u.rebuild=i.rebuild(u.rebuild,f.rebuild),c},i.build=function(e,t){return e&&t?function(r,s){return t(e(r,s),s)}:e||t},i.coerce=function(e,t){return e&&t?{from:e.from&&t.from?[...new Set([...e.from,...t.from])]:null,method(r,s){let n;if((!t.from||t.from.includes(typeof r))&&(n=t.method(r,s),n)){if(n.errors||void 0===n.value)return n;r=n.value}if(!e.from||e.from.includes(typeof r)){const t=e.method(r,s);if(t)return t}return n}}:e||t},i.prepare=function(e,t){return e&&t?function(r,s){const n=e(r,s);if(n){if(n.errors||void 0===n.value)return n;r=n.value}return t(r,s)||n}:e||t},i.rebuild=function(e,t){return e&&t?function(r){t(r),e(r)}:e||t},i.validate=function(e,t){return e&&t?function(r,s){const n=t(r,s);if(n){if(n.errors&&(!Array.isArray(n.errors)||n.errors.length))return n;r=n.value}return e(r,s)||n}:e||t}},function(e,t){},function(e,t){},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(14),o={};e.exports=o.merge=function(e,t,r){if(s(e&&"object"==typeof e,"Invalid target value: must be an object"),s(null==t||"object"==typeof t,"Invalid source value: must be null, undefined, or an object"),!t)return e;if(r=Object.assign({nullOverride:!0,mergeArrays:!0},r),Array.isArray(t)){s(Array.isArray(e),"Cannot merge array onto an object"),r.mergeArrays||(e.length=0);for(let s=0;s<t.length;++s)e.push(n(t[s],{symbols:r.symbols}));return e}const i=a.keys(t,r);for(let s=0;s<i.length;++s){const a=i[s];if("__proto__"===a||!Object.prototype.propertyIsEnumerable.call(t,a))continue;const l=t[a];if(l&&"object"==typeof l){if(e[a]===l)continue;!e[a]||"object"!=typeof e[a]||Array.isArray(e[a])!==Array.isArray(l)||l instanceof Date||l instanceof RegExp?e[a]=n(l,{symbols:r.symbols}):o.merge(e[a],l,r)}else(null!=l||r.nullOverride)&&(e[a]=l)}return e}},function(e,t,r){"use strict";const s=r(0),n=r(10),a=r(1),o={};e.exports=o.Values=class{constructor(e,t){this._values=new Set(e),this._refs=new Set(t),this._lowercase=o.lowercases(e),this._override=!1}get length(){return this._values.size+this._refs.size}add(e,t){a.isResolvable(e)?this._refs.has(e)||(this._refs.add(e),t&&t.register(e)):this.has(e,null,null,!1)||(this._values.add(e),"string"==typeof e&&this._lowercase.set(e.toLowerCase(),e))}static merge(e,t,r){if(e=e||new o.Values,t){if(t._override)return t.clone();for(const r of[...t._values,...t._refs])e.add(r)}if(r)for(const t of[...r._values,...r._refs])e.remove(t);return e.length?e:null}remove(e){a.isResolvable(e)?this._refs.delete(e):(this._values.delete(e),"string"==typeof e&&this._lowercase.delete(e.toLowerCase()))}has(e,t,r,s){return!!this.get(e,t,r,s)}get(e,t,r,s){if(!this.length)return!1;if(this._values.has(e))return{value:e};if("string"==typeof e&&e&&s){const t=this._lowercase.get(e.toLowerCase());if(t)return{value:t}}if(!this._refs.size&&"object"!=typeof e)return!1;if("object"==typeof e)for(const t of this._values)if(n(t,e))return{value:t};if(t)for(const a of this._refs){const o=a.resolve(e,t,r,null,{in:!0});if(void 0===o)continue;const i=a.in&&"object"==typeof o?Array.isArray(o)?o:Object.keys(o):[o];for(const t of i)if(typeof t==typeof e)if(s&&e&&"string"==typeof e){if(t.toLowerCase()===e.toLowerCase())return{value:t,ref:a}}else if(n(t,e))return{value:t,ref:a}}return!1}override(){this._override=!0}values(e){if(e&&e.display){const e=[];for(const t of[...this._values,...this._refs])void 0!==t&&e.push(t);return e}return Array.from([...this._values,...this._refs])}clone(){const e=new o.Values(this._values,this._refs);return e._override=this._override,e}concat(e){s(!e._override,"Cannot concat override set of values");const t=new o.Values([...this._values,...e._values],[...this._refs,...e._refs]);return t._override=this._override,t}describe(){const e=[];this._override&&e.push({override:!0});for(const t of this._values.values())e.push(t&&"object"==typeof t?{value:t}:t);for(const t of this._refs.values())e.push(t.describe());return e}},o.Values.prototype[a.symbols.values]=!0,o.Values.prototype.slice=o.Values.prototype.clone,o.lowercases=function(e){const t=new Map;if(e)for(const r of e)"string"==typeof r&&t.set(r.toLowerCase(),r);return t}},function(e,t,r){"use strict";const s=r(43),n=r(0),a=r(2),o=r(44),i=r(3),l=r(1),c=r(8),u=r(4),f=r(5),m=r(7),h={renameDefaults:{alias:!1,multiple:!1,override:!1}};e.exports=i.extend({type:"_keys",properties:{typeof:"object"},flags:{unknown:{default:!1}},terms:{dependencies:{init:null},keys:{init:null,manifest:{mapped:{from:"schema",to:"key"}}},patterns:{init:null},renames:{init:null}},args:(e,t)=>e.keys(t),validate(e,{schema:t,error:r,state:s,prefs:n}){if(!e||typeof e!==t.$_property("typeof")||Array.isArray(e))return{value:e,errors:r("object.base",{type:t.$_property("typeof")})};if(!(t.$_terms.renames||t.$_terms.dependencies||t.$_terms.keys||t.$_terms.patterns||t.$_terms.externals))return;e=h.clone(e,n);const a=[];if(t.$_terms.renames&&!h.rename(t,e,s,n,a))return{value:e,errors:a};if(!t.$_terms.keys&&!t.$_terms.patterns&&!t.$_terms.dependencies)return{value:e,errors:a};const o=new Set(Object.keys(e));if(t.$_terms.keys){const r=[e,...s.ancestors];for(const i of t.$_terms.keys){const t=i.key,l=e[t];o.delete(t);const c=s.localize([...s.path,t],r,i),u=i.schema.$_validate(l,c,n);if(u.errors){if(n.abortEarly)return{value:e,errors:u.errors};a.push(...u.errors)}else"strip"===i.schema._flags.result||void 0===u.value&&void 0!==l?delete e[t]:void 0!==u.value&&(e[t]=u.value)}}if(o.size||t._flags._hasPatternMatch){const r=h.unknown(t,e,o,a,s,n);if(r)return r}if(t.$_terms.dependencies)for(const r of t.$_terms.dependencies){if(r.key&&void 0===r.key.resolve(e,s,n,null,{shadow:!1}))continue;const o=h.dependencies[r.rel](t,r,e,s,n);if(o){const r=t.$_createError(o.code,e,o.context,s,n);if(n.abortEarly)return{value:e,errors:r};a.push(r)}}return{value:e,errors:a}},rules:{and:{method(...e){return l.verifyFlat(e,"and"),h.dependency(this,"and",null,e)}},append:{method(e){return null==e||0===Object.keys(e).length?this:this.keys(e)}},assert:{method(e,t,r){m.isTemplate(e)||(e=c.ref(e)),n(void 0===r||"string"==typeof r,"Message must be a string"),t=this.$_compile(t,{appendPath:!0});const s=this.$_addRule({name:"assert",args:{subject:e,schema:t,message:r}});return s.$_mutateRegister(e),s.$_mutateRegister(t),s},validate(e,{error:t,prefs:r,state:s},{subject:n,schema:a,message:o}){const i=n.resolve(e,s,r),l=f.isRef(n)?n.absolute(s):[];return a.$_match(i,s.localize(l,[e,...s.ancestors],a),r)?e:t("object.assert",{subject:n,message:o})},args:["subject","schema","message"],multi:!0},instance:{method(e,t){return n("function"==typeof e,"constructor must be a function"),t=t||e.name,this.$_addRule({name:"instance",args:{constructor:e,name:t}})},validate:(e,t,{constructor:r,name:s})=>e instanceof r?e:t.error("object.instance",{type:s,value:e}),args:["constructor","name"]},keys:{method(e){n(void 0===e||"object"==typeof e,"Object schema must be a valid object"),n(!l.isSchema(e),"Object schema cannot be a joi schema");const t=this.clone();if(e)if(Object.keys(e).length){t.$_terms.keys=t.$_terms.keys?t.$_terms.keys.filter(t=>!e.hasOwnProperty(t.key)):new h.Keys;for(const r in e)l.tryWithPath(()=>t.$_terms.keys.push({key:r,schema:this.$_compile(e[r])}),r)}else t.$_terms.keys=new h.Keys;else t.$_terms.keys=null;return t.$_mutateRebuild()}},length:{method(e){return this.$_addRule({name:"length",args:{limit:e},operator:"="})},validate:(e,t,{limit:r},{name:s,operator:n,args:a})=>l.compare(Object.keys(e).length,r,n)?e:t.error("object."+s,{limit:a.limit,value:e}),args:[{name:"limit",ref:!0,assert:l.limit,message:"must be a positive integer"}]},max:{method(e){return this.$_addRule({name:"max",method:"length",args:{limit:e},operator:"<="})}},min:{method(e){return this.$_addRule({name:"min",method:"length",args:{limit:e},operator:">="})}},nand:{method(...e){return l.verifyFlat(e,"nand"),h.dependency(this,"nand",null,e)}},or:{method(...e){return l.verifyFlat(e,"or"),h.dependency(this,"or",null,e)}},oxor:{method(...e){return h.dependency(this,"oxor",null,e)}},pattern:{method(e,t,r={}){const s=e instanceof RegExp;s||(e=this.$_compile(e,{appendPath:!0})),n(void 0!==t,"Invalid rule"),l.assertOptions(r,["fallthrough","matches"]),s&&n(!e.flags.includes("g")&&!e.flags.includes("y"),"pattern should not use global or sticky mode"),t=this.$_compile(t,{appendPath:!0});const a=this.clone();a.$_terms.patterns=a.$_terms.patterns||[];const o={[s?"regex":"schema"]:e,rule:t};return r.matches&&(o.matches=this.$_compile(r.matches),"array"!==o.matches.type&&(o.matches=o.matches.$_root.array().items(o.matches)),a.$_mutateRegister(o.matches),a.$_setFlag("_hasPatternMatch",!0,{clone:!1})),r.fallthrough&&(o.fallthrough=!0),a.$_terms.patterns.push(o),a.$_mutateRegister(t),a}},ref:{method(){return this.$_addRule("ref")},validate:(e,t)=>f.isRef(e)?e:t.error("object.refType",{value:e})},regex:{method(){return this.$_addRule("regex")},validate:(e,t)=>e instanceof RegExp?e:t.error("object.regex",{value:e})},rename:{method(e,t,r={}){n("string"==typeof e||e instanceof RegExp,"Rename missing the from argument"),n("string"==typeof t||t instanceof m,"Invalid rename to argument"),n(t!==e,"Cannot rename key to same name:",e),l.assertOptions(r,["alias","ignoreUndefined","override","multiple"]);const a=this.clone();a.$_terms.renames=a.$_terms.renames||[];for(const t of a.$_terms.renames)n(t.from!==e,"Cannot rename the same key multiple times");return t instanceof m&&a.$_mutateRegister(t),a.$_terms.renames.push({from:e,to:t,options:s(h.renameDefaults,r)}),a}},schema:{method(e="any"){return this.$_addRule({name:"schema",args:{type:e}})},validate:(e,t,{type:r})=>!l.isSchema(e)||"any"!==r&&e.type!==r?t.error("object.schema",{type:r}):e},unknown:{method(e){return this.$_setFlag("unknown",!1!==e)}},with:{method(e,t,r={}){return h.dependency(this,"with",e,t,r)}},without:{method(e,t,r={}){return h.dependency(this,"without",e,t,r)}},xor:{method(...e){return l.verifyFlat(e,"xor"),h.dependency(this,"xor",null,e)}}},overrides:{default(e,t){return void 0===e&&(e=l.symbols.deepDefault),this.$_parent("default",e,t)}},rebuild(e){if(e.$_terms.keys){const t=new o.Sorter;for(const r of e.$_terms.keys)l.tryWithPath(()=>t.add(r,{after:r.schema.$_rootReferences(),group:r.key}),r.key);e.$_terms.keys=new h.Keys(...t.nodes)}},manifest:{build(e,t){if(t.keys&&(e=e.keys(t.keys)),t.dependencies)for(const{rel:r,key:s=null,peers:n,options:a}of t.dependencies)e=h.dependency(e,r,s,n,a);if(t.patterns)for(const{regex:r,schema:s,rule:n,fallthrough:a,matches:o}of t.patterns)e=e.pattern(r||s,n,{fallthrough:a,matches:o});if(t.renames)for(const{from:r,to:s,options:n}of t.renames)e=e.rename(r,s,n);return e}},messages:{"object.and":"{{#label}} contains {{#presentWithLabels}} without its required peers {{#missingWithLabels}}","object.assert":'{{#label}} is invalid because {if(#subject.key, `"` + #subject.key + `" failed to ` + (#message || "pass the assertion test"), #message || "the assertion failed")}',"object.base":"{{#label}} must be of type {{#type}}","object.instance":"{{#label}} must be an instance of {{:#type}}","object.length":'{{#label}} must have {{#limit}} key{if(#limit == 1, "", "s")}',"object.max":'{{#label}} must have less than or equal to {{#limit}} key{if(#limit == 1, "", "s")}',"object.min":'{{#label}} must have at least {{#limit}} key{if(#limit == 1, "", "s")}',"object.missing":"{{#label}} must contain at least one of {{#peersWithLabels}}","object.nand":"{{:#mainWithLabel}} must not exist simultaneously with {{#peersWithLabels}}","object.oxor":"{{#label}} contains a conflict between optional exclusive peers {{#peersWithLabels}}","object.pattern.match":"{{#label}} keys failed to match pattern requirements","object.refType":"{{#label}} must be a Joi reference","object.regex":"{{#label}} must be a RegExp object","object.rename.multiple":"{{#label}} cannot rename {{:#from}} because multiple renames are disabled and another key was already renamed to {{:#to}}","object.rename.override":"{{#label}} cannot rename {{:#from}} because override is disabled and target {{:#to}} exists","object.schema":"{{#label}} must be a Joi schema of {{#type}} type","object.unknown":"{{#label}} is not allowed","object.with":"{{:#mainWithLabel}} missing required peer {{:#peerWithLabel}}","object.without":"{{:#mainWithLabel}} conflict with forbidden peer {{:#peerWithLabel}}","object.xor":"{{#label}} contains a conflict between exclusive peers {{#peersWithLabels}}"}}),h.clone=function(e,t){if("object"==typeof e){if(t.nonEnumerables)return a(e,{shallow:!0});const r=Object.create(Object.getPrototypeOf(e));return Object.assign(r,e),r}const r=function(...t){return e.apply(this,t)};return r.prototype=a(e.prototype),Object.defineProperty(r,"name",{value:e.name,writable:!1}),Object.defineProperty(r,"length",{value:e.length,writable:!1}),Object.assign(r,e),r},h.dependency=function(e,t,r,s,a){n(null===r||"string"==typeof r,t,"key must be a strings"),a||(a=s.length>1&&"object"==typeof s[s.length-1]?s.pop():{}),l.assertOptions(a,["separator"]),s=[].concat(s);const o=l.default(a.separator,"."),i=[];for(const e of s)n("string"==typeof e,t,"peers must be a string or a reference"),i.push(c.ref(e,{separator:o,ancestor:0,prefix:!1}));null!==r&&(r=c.ref(r,{separator:o,ancestor:0,prefix:!1}));const u=e.clone();return u.$_terms.dependencies=u.$_terms.dependencies||[],u.$_terms.dependencies.push(new h.Dependency(t,r,i,s)),u},h.dependencies={and(e,t,r,s,n){const a=[],o=[],i=t.peers.length;for(const e of t.peers)void 0===e.resolve(r,s,n,null,{shadow:!1})?a.push(e.key):o.push(e.key);if(a.length!==i&&o.length!==i)return{code:"object.and",context:{present:o,presentWithLabels:h.keysToLabels(e,o),missing:a,missingWithLabels:h.keysToLabels(e,a)}}},nand(e,t,r,s,n){const a=[];for(const e of t.peers)void 0!==e.resolve(r,s,n,null,{shadow:!1})&&a.push(e.key);if(a.length!==t.peers.length)return;const o=t.paths[0],i=t.paths.slice(1);return{code:"object.nand",context:{main:o,mainWithLabel:h.keysToLabels(e,o),peers:i,peersWithLabels:h.keysToLabels(e,i)}}},or(e,t,r,s,n){for(const e of t.peers)if(void 0!==e.resolve(r,s,n,null,{shadow:!1}))return;return{code:"object.missing",context:{peers:t.paths,peersWithLabels:h.keysToLabels(e,t.paths)}}},oxor(e,t,r,s,n){const a=[];for(const e of t.peers)void 0!==e.resolve(r,s,n,null,{shadow:!1})&&a.push(e.key);if(!a.length||1===a.length)return;const o={peers:t.paths,peersWithLabels:h.keysToLabels(e,t.paths)};return o.present=a,o.presentWithLabels=h.keysToLabels(e,a),{code:"object.oxor",context:o}},with(e,t,r,s,n){for(const a of t.peers)if(void 0===a.resolve(r,s,n,null,{shadow:!1}))return{code:"object.with",context:{main:t.key.key,mainWithLabel:h.keysToLabels(e,t.key.key),peer:a.key,peerWithLabel:h.keysToLabels(e,a.key)}}},without(e,t,r,s,n){for(const a of t.peers)if(void 0!==a.resolve(r,s,n,null,{shadow:!1}))return{code:"object.without",context:{main:t.key.key,mainWithLabel:h.keysToLabels(e,t.key.key),peer:a.key,peerWithLabel:h.keysToLabels(e,a.key)}}},xor(e,t,r,s,n){const a=[];for(const e of t.peers)void 0!==e.resolve(r,s,n,null,{shadow:!1})&&a.push(e.key);if(1===a.length)return;const o={peers:t.paths,peersWithLabels:h.keysToLabels(e,t.paths)};return 0===a.length?{code:"object.missing",context:o}:(o.present=a,o.presentWithLabels=h.keysToLabels(e,a),{code:"object.xor",context:o})}},h.keysToLabels=function(e,t){return Array.isArray(t)?t.map(t=>e.$_mapLabels(t)):e.$_mapLabels(t)},h.rename=function(e,t,r,s,n){const a={};for(const o of e.$_terms.renames){const i=[],l="string"!=typeof o.from;if(l)for(const e in t){if(void 0===t[e]&&o.options.ignoreUndefined)continue;if(e===o.to)continue;const r=o.from.exec(e);r&&i.push({from:e,to:o.to,match:r})}else!Object.prototype.hasOwnProperty.call(t,o.from)||void 0===t[o.from]&&o.options.ignoreUndefined||i.push(o);for(const c of i){const i=c.from;let u=c.to;if(u instanceof m&&(u=u.render(t,r,s,c.match)),i!==u){if(!o.options.multiple&&a[u]&&(n.push(e.$_createError("object.rename.multiple",t,{from:i,to:u,pattern:l},r,s)),s.abortEarly))return!1;if(Object.prototype.hasOwnProperty.call(t,u)&&!o.options.override&&!a[u]&&(n.push(e.$_createError("object.rename.override",t,{from:i,to:u,pattern:l},r,s)),s.abortEarly))return!1;void 0===t[i]?delete t[u]:t[u]=t[i],a[u]=!0,o.options.alias||delete t[i]}}}return!0},h.unknown=function(e,t,r,s,n,a){if(e.$_terms.patterns){let o=!1;const i=e.$_terms.patterns.map(e=>{if(e.matches)return o=!0,[]}),l=[t,...n.ancestors];for(const o of r){const c=t[o],u=[...n.path,o];for(let f=0;f<e.$_terms.patterns.length;++f){const m=e.$_terms.patterns[f];if(m.regex){const e=m.regex.test(o);if(n.mainstay.tracer.debug(n,"rule","pattern.".concat(f),e?"pass":"error"),!e)continue}else if(!m.schema.$_match(o,n.nest(m.schema,"pattern.".concat(f)),a))continue;r.delete(o);const h=n.localize(u,l,{schema:m.rule,key:o}),p=m.rule.$_validate(c,h,a);if(p.errors){if(a.abortEarly)return{value:t,errors:p.errors};s.push(...p.errors)}if(m.matches&&i[f].push(o),t[o]=p.value,!m.fallthrough)break}}if(o)for(let r=0;r<i.length;++r){const o=i[r];if(!o)continue;const c=e.$_terms.patterns[r].matches,f=n.localize(n.path,l,c),m=c.$_validate(o,f,a);if(m.errors){const r=u.details(m.errors,{override:!1});r.matches=o;const i=e.$_createError("object.pattern.match",t,r,n,a);if(a.abortEarly)return{value:t,errors:i};s.push(i)}}}if(!r.size||!e.$_terms.keys&&!e.$_terms.patterns)return;if(a.stripUnknown&&!e._flags.unknown||a.skipFunctions){const e=!!a.stripUnknown&&(!0===a.stripUnknown||!!a.stripUnknown.objects);for(const s of r)e?(delete t[s],r.delete(s)):"function"==typeof t[s]&&r.delete(s)}if(!l.default(e._flags.unknown,a.allowUnknown))for(const o of r){const r=n.localize([...n.path,o],[]),i=e.$_createError("object.unknown",t[o],{child:o},r,a,{flags:!1});if(a.abortEarly)return{value:t,errors:i};s.push(i)}},h.Dependency=class{constructor(e,t,r,s){this.rel=e,this.key=t,this.peers=r,this.paths=s}describe(){const e={rel:this.rel,peers:this.paths};return null!==this.key&&(e.key=this.key.key),"."!==this.peers[0].separator&&(e.options={separator:this.peers[0].separator}),e}},h.Keys=class extends Array{concat(e){const t=this.slice(),r=new Map;for(let e=0;e<t.length;++e)r.set(t[e].key,e);for(const s of e){const e=s.key,n=r.get(e);void 0!==n?t[n]={key:e,schema:t[n].schema.concat(s.schema)}:t.push(s)}return t}}},function(e,t,r){"use strict";const s=r(24),n=r(25),a={minDomainSegments:2,nonAsciiRx:/[^\x00-\x7f]/,domainControlRx:/[\x00-\x20@\:\/]/,tldSegmentRx:/^[a-zA-Z](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,domainSegmentRx:/^[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,URL:s.URL||URL};t.analyze=function(e,t={}){if("string"!=typeof e)throw new Error("Invalid input: domain must be a string");if(!e)return n.code("DOMAIN_NON_EMPTY_STRING");if(e.length>256)return n.code("DOMAIN_TOO_LONG");if(!!a.nonAsciiRx.test(e)){if(!1===t.allowUnicode)return n.code("DOMAIN_INVALID_UNICODE_CHARS");e=e.normalize("NFC")}if(a.domainControlRx.test(e))return n.code("DOMAIN_INVALID_CHARS");e=a.punycode(e);const r=t.minDomainSegments||a.minDomainSegments,s=e.split(".");if(s.length<r)return n.code("DOMAIN_SEGMENTS_COUNT");if(t.maxDomainSegments&&s.length>t.maxDomainSegments)return n.code("DOMAIN_SEGMENTS_COUNT_MAX");const o=t.tlds;if(o){const e=s[s.length-1].toLowerCase();if(o.deny&&o.deny.has(e)||o.allow&&!o.allow.has(e))return n.code("DOMAIN_FORBIDDEN_TLDS")}for(let e=0;e<s.length;++e){const t=s[e];if(!t.length)return n.code("DOMAIN_EMPTY_SEGMENT");if(t.length>63)return n.code("DOMAIN_LONG_SEGMENT");if(e<s.length-1){if(!a.domainSegmentRx.test(t))return n.code("DOMAIN_INVALID_CHARS")}else if(!a.tldSegmentRx.test(t))return n.code("DOMAIN_INVALID_TLDS_CHARS")}return null},t.isValid=function(e,r){return!t.analyze(e,r)},a.punycode=function(e){try{return new a.URL("http://".concat(e)).host}catch(t){return e}}},function(e,t){},function(e,t,r){"use strict";t.codes={EMPTY_STRING:"Address must be a non-empty string",FORBIDDEN_UNICODE:"Address contains forbidden Unicode characters",MULTIPLE_AT_CHAR:"Address cannot contain more than one @ character",MISSING_AT_CHAR:"Address must contain one @ character",EMPTY_LOCAL:"Address local part cannot be empty",ADDRESS_TOO_LONG:"Address too long",LOCAL_TOO_LONG:"Address local part too long",EMPTY_LOCAL_SEGMENT:"Address local part contains empty dot-separated segment",INVALID_LOCAL_CHARS:"Address local part contains invalid character",DOMAIN_NON_EMPTY_STRING:"Domain must be a non-empty string",DOMAIN_TOO_LONG:"Domain too long",DOMAIN_INVALID_UNICODE_CHARS:"Domain contains forbidden Unicode characters",DOMAIN_INVALID_CHARS:"Domain contains invalid character",DOMAIN_INVALID_TLDS_CHARS:"Domain contains invalid tld character",DOMAIN_SEGMENTS_COUNT:"Domain lacks the minimum required number of segments",DOMAIN_SEGMENTS_COUNT_MAX:"Domain contains too many segments",DOMAIN_FORBIDDEN_TLDS:"Domain uses forbidden TLD",DOMAIN_EMPTY_SEGMENT:"Domain contains empty dot-separated segment",DOMAIN_LONG_SEGMENT:"Domain contains dot-separated segment that is too long"},t.code=function(e){return{code:e,error:t.codes[e]}}},function(e,t,r){"use strict";const s=r(0),n=r(27),a={generate:function(){const e={},t="!\\$&'\\(\\)\\*\\+,;=",r="\\w-\\.~%\\dA-Fa-f"+t+":@",s="["+r+"]",n="(?:0{0,2}\\d|0?[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";e.ipv4address="(?:"+n+"\\.){3}"+n;const a="[\\dA-Fa-f]{1,4}",o="(?:"+a+":"+a+"|"+e.ipv4address+")",i="(?:"+a+":){6}"+o,l="::(?:"+a+":){5}"+o,c="(?:"+a+")?::(?:"+a+":){4}"+o,u="(?:(?:"+a+":){0,1}"+a+")?::(?:"+a+":){3}"+o,f="(?:(?:"+a+":){0,2}"+a+")?::(?:"+a+":){2}"+o,m="(?:(?:"+a+":){0,3}"+a+")?::"+a+":"+o,h="(?:(?:"+a+":){0,4}"+a+")?::"+o;e.ipv4Cidr="(?:\\d|[1-2]\\d|3[0-2])",e.ipv6Cidr="(?:0{0,2}\\d|0?[1-9]\\d|1[01]\\d|12[0-8])",e.ipv6address="(?:"+i+"|"+l+"|"+c+"|"+u+"|"+f+"|"+m+"|"+h+"|(?:(?:[\\dA-Fa-f]{1,4}:){0,5}[\\dA-Fa-f]{1,4})?::[\\dA-Fa-f]{1,4}|(?:(?:[\\dA-Fa-f]{1,4}:){0,6}[\\dA-Fa-f]{1,4})?::)",e.ipvFuture="v[\\dA-Fa-f]+\\.[\\w-\\.~"+t+":]+",e.scheme="[a-zA-Z][a-zA-Z\\d+-\\.]*",e.schemeRegex=new RegExp(e.scheme);const p="[\\w-\\.~%\\dA-Fa-f"+t+":]*",d="(?:"+("\\[(?:"+e.ipv6address+"|"+e.ipvFuture+")\\]")+"|"+e.ipv4address+"|[\\w-\\.~%\\dA-Fa-f!\\$&'\\(\\)\\*\\+,;=]{1,255})",g="(?:"+p+"@)?"+d+"(?::\\d*)?",y="(?:"+p+"@)?("+d+")(?::\\d*)?",b=s+"*",v=s+"+",_="(?:\\/"+b+")*",w="\\/(?:"+v+_+")?",$=v+_,x="[\\w-\\.~%\\dA-Fa-f!\\$&'\\(\\)\\*\\+,;=@]+"+_;return e.hierPart="(?:(?:\\/\\/"+g+_+")|"+w+"|"+$+"|(?:\\/\\/\\/[\\w-\\.~%\\dA-Fa-f!\\$&'\\(\\)\\*\\+,;=:@]*(?:\\/[\\w-\\.~%\\dA-Fa-f!\\$&'\\(\\)\\*\\+,;=:@]*)*))",e.hierPartCapture="(?:(?:\\/\\/"+y+_+")|"+w+"|"+$+")",e.relativeRef="(?:(?:\\/\\/"+g+_+")|"+w+"|"+x+"|)",e.relativeRefCapture="(?:(?:\\/\\/"+y+_+")|"+w+"|"+x+"|)",e.query="["+r+"\\/\\?]*(?=#|$)",e.queryWithSquareBrackets="["+r+"\\[\\]\\/\\?]*(?=#|$)",e.fragment="["+r+"\\/\\?]*",e}};a.rfc3986=a.generate(),t.ip={v4Cidr:a.rfc3986.ipv4Cidr,v6Cidr:a.rfc3986.ipv6Cidr,ipv4:a.rfc3986.ipv4address,ipv6:a.rfc3986.ipv6address,ipvfuture:a.rfc3986.ipvFuture},a.createRegex=function(e){const t=a.rfc3986,r="(?:\\?"+(e.allowQuerySquareBrackets?t.queryWithSquareBrackets:t.query)+")?(?:#"+t.fragment+")?",o=e.domain?t.relativeRefCapture:t.relativeRef;if(e.relativeOnly)return a.wrap(o+r);let i="";if(e.scheme){s(e.scheme instanceof RegExp||"string"==typeof e.scheme||Array.isArray(e.scheme),"scheme must be a RegExp, String, or Array");const r=[].concat(e.scheme);s(r.length>=1,"scheme must have at least 1 scheme specified");const a=[];for(let e=0;e<r.length;++e){const o=r[e];s(o instanceof RegExp||"string"==typeof o,"scheme at position "+e+" must be a RegExp or String"),o instanceof RegExp?a.push(o.source.toString()):(s(t.schemeRegex.test(o),"scheme at position "+e+" must be a valid scheme"),a.push(n(o)))}i=a.join("|")}const l="(?:"+(i?"(?:"+i+")":t.scheme)+":"+(e.domain?t.hierPartCapture:t.hierPart)+")",c=e.allowRelative?"(?:"+l+"|"+o+")":l;return a.wrap(c+r,i)},a.wrap=function(e,t){return{raw:e="(?=.)(?!https?:/$)".concat(e),regex:new RegExp("^".concat(e,"$")),scheme:t}},a.uriRegex=a.createRegex({}),t.regex=function(e={}){return e.scheme||e.allowRelative||e.relativeOnly||e.allowQuerySquareBrackets||e.domain?a.createRegex(e):a.uriRegex}},function(e,t,r){"use strict";e.exports=function(e){return e.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g,"\\$&")}},function(e,t,r){"use strict";e.exports=function(...e){try{return JSON.stringify.apply(null,e)}catch(e){return"[Cannot display object: "+e.message+"]"}}},function(e){e.exports=JSON.parse('{"version":"17.3.0"}')},function(e,t,r){"use strict";const s={};e.exports=function(e){if(!e)return"";let t="";for(let r=0;r<e.length;++r){const n=e.charCodeAt(r);s.isSafe(n)?t+=e[r]:t+=s.escapeHtmlChar(n)}return t},s.escapeHtmlChar=function(e){const t=s.namedHtml[e];if(void 0!==t)return t;if(e>=256)return"&#"+e+";";const r=e.toString(16).padStart(2,"0");return"&#x".concat(r,";")},s.isSafe=function(e){return void 0!==s.safeCharCodes[e]},s.namedHtml={38:"&amp;",60:"&lt;",62:"&gt;",34:"&quot;",160:"&nbsp;",162:"&cent;",163:"&pound;",164:"&curren;",169:"&copy;",174:"&reg;"},s.safeCharCodes=function(){const e={};for(let t=32;t<123;++t)(t>=97||t>=65&&t<=90||t>=48&&t<=57||32===t||46===t||44===t||45===t||58===t||95===t)&&(e[t]=null);return e}()},function(e,t,r){"use strict";const s={operators:["!","^","*","/","%","+","-","<","<=",">",">=","==","!=","&&","||","??"],operatorCharacters:["!","^","*","/","%","+","-","<","=",">","&","|","?"],operatorsOrder:[["^"],["*","/","%"],["+","-"],["<","<=",">",">="],["==","!="],["&&"],["||","??"]],operatorsPrefix:["!","n"],literals:{'"':'"',"`":"`","'":"'","[":"]"},numberRx:/^(?:[0-9]*\.?[0-9]*){1}$/,tokenRx:/^[\w\$\#\.\@\:\{\}]+$/,symbol:Symbol("formula"),settings:Symbol("settings")};t.Parser=class{constructor(e,t={}){if(!t[s.settings]&&t.constants)for(const e in t.constants){const r=t.constants[e];if(null!==r&&!["boolean","number","string"].includes(typeof r))throw new Error("Formula constant ".concat(e," contains invalid ").concat(typeof r," value type"))}this.settings=t[s.settings]?t:Object.assign({[s.settings]:!0,constants:{},functions:{}},t),this.single=null,this._parts=null,this._parse(e)}_parse(e){let r=[],n="",a=0,o=!1;const i=e=>{if(a)throw new Error("Formula missing closing parenthesis");const i=r.length?r[r.length-1]:null;if(o||n||e){if(i&&"reference"===i.type&&")"===e)return i.type="function",i.value=this._subFormula(n,i.value),void(n="");if(")"===e){const e=new t.Parser(n,this.settings);r.push({type:"segment",value:e})}else if(o){if("]"===o)return r.push({type:"reference",value:n}),void(n="");r.push({type:"literal",value:n})}else if(s.operatorCharacters.includes(n))i&&"operator"===i.type&&s.operators.includes(i.value+n)?i.value+=n:r.push({type:"operator",value:n});else if(n.match(s.numberRx))r.push({type:"constant",value:parseFloat(n)});else if(void 0!==this.settings.constants[n])r.push({type:"constant",value:this.settings.constants[n]});else{if(!n.match(s.tokenRx))throw new Error("Formula contains invalid token: ".concat(n));r.push({type:"reference",value:n})}n=""}};for(const t of e)o?t===o?(i(),o=!1):n+=t:a?"("===t?(n+=t,++a):")"===t?(--a,a?n+=t:i(t)):n+=t:t in s.literals?o=s.literals[t]:"("===t?(i(),++a):s.operatorCharacters.includes(t)?(i(),n=t,i()):" "!==t?n+=t:i();i(),r=r.map((e,t)=>"operator"!==e.type||"-"!==e.value||t&&"operator"!==r[t-1].type?e:{type:"operator",value:"n"});let l=!1;for(const e of r){if("operator"===e.type){if(s.operatorsPrefix.includes(e.value))continue;if(!l)throw new Error("Formula contains an operator in invalid position");if(!s.operators.includes(e.value))throw new Error("Formula contains an unknown operator ".concat(e.value))}else if(l)throw new Error("Formula missing expected operator");l=!l}if(!l)throw new Error("Formula contains invalid trailing operator");1===r.length&&["reference","literal","constant"].includes(r[0].type)&&(this.single={type:"reference"===r[0].type?"reference":"value",value:r[0].value}),this._parts=r.map(e=>{if("operator"===e.type)return s.operatorsPrefix.includes(e.value)?e:e.value;if("reference"!==e.type)return e.value;if(this.settings.tokenRx&&!this.settings.tokenRx.test(e.value))throw new Error("Formula contains invalid reference ".concat(e.value));return this.settings.reference?this.settings.reference(e.value):s.reference(e.value)})}_subFormula(e,r){const n=this.settings.functions[r];if("function"!=typeof n)throw new Error("Formula contains unknown function ".concat(r));let a=[];if(e){let t="",n=0,o=!1;const i=()=>{if(!t)throw new Error("Formula contains function ".concat(r," with invalid arguments ").concat(e));a.push(t),t=""};for(let r=0;r<e.length;++r){const a=e[r];o?(t+=a,a===o&&(o=!1)):a in s.literals&&!n?(t+=a,o=s.literals[a]):","!==a||n?(t+=a,"("===a?++n:")"===a&&--n):i()}i()}return a=a.map(e=>new t.Parser(e,this.settings)),function(e){const t=[];for(const r of a)t.push(r.evaluate(e));return n.call(e,...t)}}evaluate(e){const t=this._parts.slice();for(let r=t.length-2;r>=0;--r){const n=t[r];if(n&&"operator"===n.type){const a=t[r+1];t.splice(r+1,1);const o=s.evaluate(a,e);t[r]=s.single(n.value,o)}}return s.operatorsOrder.forEach(r=>{for(let n=1;n<t.length-1;)if(r.includes(t[n])){const r=t[n],a=s.evaluate(t[n-1],e),o=s.evaluate(t[n+1],e);t.splice(n,2);const i=s.calculate(r,a,o);t[n-1]=0===i?0:i}else n+=2}),s.evaluate(t[0],e)}},t.Parser.prototype[s.symbol]=!0,s.reference=function(e){return function(t){return t&&void 0!==t[e]?t[e]:null}},s.evaluate=function(e,t){return null===e?null:"function"==typeof e?e(t):e[s.symbol]?e.evaluate(t):e},s.single=function(e,t){if("!"===e)return!t;const r=-t;return 0===r?0:r},s.calculate=function(e,t,r){if("??"===e)return s.exists(t)?t:r;if("string"==typeof t||"string"==typeof r){if("+"===e)return(t=s.exists(t)?t:"")+(r=s.exists(r)?r:"")}else switch(e){case"^":return Math.pow(t,r);case"*":return t*r;case"/":return t/r;case"%":return t%r;case"+":return t+r;case"-":return t-r}switch(e){case"<":return t<r;case"<=":return t<=r;case">":return t>r;case">=":return t>=r;case"==":return t===r;case"!=":return t!==r;case"&&":return t&&r;case"||":return t||r}return null},s.exists=function(e){return null!=e}},function(e,t){},function(e,t,r){"use strict";const s=r(0),n=r(3),a=r(1),o=r(8),i=r(4),l=r(5),c={};e.exports=n.extend({type:"alternatives",flags:{match:{default:"any"}},terms:{matches:{init:[],register:l.toSibling}},args:(e,...t)=>1===t.length&&Array.isArray(t[0])?e.try(...t[0]):e.try(...t),validate(e,t){const{schema:r,error:s,state:n,prefs:a}=t;if(r._flags.match){let t,o=0;for(let s=0;s<r.$_terms.matches.length;++s){const i=r.$_terms.matches[s],l=n.nest(i.schema,"match.".concat(s));l.snapshot();const c=i.schema.$_validate(e,l,a);c.errors?l.restore():(++o,t=c.value)}return o?"one"===r._flags.match?1===o?{value:t}:{errors:s("alternatives.one")}:o===r.$_terms.matches.length?{value:e}:{errors:s("alternatives.all")}:{errors:s("alternatives.any")}}const o=[];for(let t=0;t<r.$_terms.matches.length;++t){const s=r.$_terms.matches[t];if(s.schema){const r=n.nest(s.schema,"match.".concat(t));r.snapshot();const i=s.schema.$_validate(e,r,a);if(!i.errors)return i;r.restore(),o.push({schema:s.schema,reports:i.errors});continue}const i=s.ref?s.ref.resolve(e,n,a):e,l=s.is?[s]:s.switch;for(let r=0;r<l.length;++r){const o=l[r],{is:c,then:u,otherwise:f}=o,m="match.".concat(t).concat(s.switch?"."+r:"");if(c.$_match(i,n.nest(c,"".concat(m,".is")),a)){if(u)return u.$_validate(e,n.nest(u,"".concat(m,".then")),a)}else if(f)return f.$_validate(e,n.nest(f,"".concat(m,".otherwise")),a)}}return c.errors(o,t)},rules:{conditional:{method(e,t){s(!this._flags._endedSwitch,"Unreachable condition"),s(!this._flags.match,"Cannot combine match mode",this._flags.match,"with conditional rule"),s(void 0===t.break,"Cannot use break option with alternatives conditional");const r=this.clone(),n=o.when(r,e,t),a=n.is?[n]:n.switch;for(const e of a)if(e.then&&e.otherwise){r.$_setFlag("_endedSwitch",!0,{clone:!1});break}return r.$_terms.matches.push(n),r.$_mutateRebuild()}},match:{method(e){if(s(["any","one","all"].includes(e),"Invalid alternatives match mode",e),"any"!==e)for(const t of this.$_terms.matches)s(t.schema,"Cannot combine match mode",e,"with conditional rules");return this.$_setFlag("match",e)}},try:{method(...e){s(e.length,"Missing alternative schemas"),a.verifyFlat(e,"try"),s(!this._flags._endedSwitch,"Unreachable condition");const t=this.clone();for(const r of e)t.$_terms.matches.push({schema:t.$_compile(r)});return t.$_mutateRebuild()}}},overrides:{label(e){return this.$_parent("label",e).$_modify({each:(t,r)=>"is"!==r.path[0]?t.label(e):void 0,ref:!1})}},rebuild(e){e.$_modify({each:t=>{a.isSchema(t)&&"array"===t.type&&e.$_setFlag("_arrayItems",!0,{clone:!1})}})},manifest:{build(e,t){if(t.matches)for(const r of t.matches){const{schema:t,ref:s,is:n,not:a,then:o,otherwise:i}=r;e=t?e.try(t):s?e.conditional(s,{is:n,then:o,not:a,otherwise:i,switch:r.switch}):e.conditional(n,{then:o,otherwise:i})}return e}},messages:{"alternatives.all":"{{#label}} does not match all of the required types","alternatives.any":"{{#label}} does not match any of the allowed types","alternatives.match":"{{#label}} does not match any of the allowed types","alternatives.one":"{{#label}} matches more than one allowed type","alternatives.types":"{{#label}} must be one of {{#types}}"}}),c.errors=function(e,{error:t,state:r}){if(!e.length)return{errors:t("alternatives.any")};if(1===e.length)return{errors:e[0].reports};const s=new Set,n=[];for(const{reports:a,schema:o}of e){if(a.length>1)return c.unmatched(e,t);const l=a[0];if(l instanceof i.Report==!1)return c.unmatched(e,t);if(l.state.path.length!==r.path.length){n.push({type:o.type,report:l});continue}if("any.only"===l.code){for(const e of l.local.valids)s.add(e);continue}const[u,f]=l.code.split(".");"base"===f?s.add(u):n.push({type:o.type,report:l})}return n.length?1===n.length?{errors:n[0].report}:c.unmatched(e,t):{errors:t("alternatives.types",{types:[...s]})}},c.unmatched=function(e,t){const r=[];for(const t of e)r.push(...t.reports);return{errors:t("alternatives.match",i.details(r,{override:!1}))}}},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(10),o=r(20),i=r(15),l=r(1),c=r(8),u=r(4),f=r(17),m=r(18),h=r(9),p=r(35),d=r(5),g=r(19),y=r(36),b=r(21),v={Base:class{constructor(e){this.type=e,this.$_root=null,this._definition={},this._reset()}_reset(){this._ids=new p.Ids,this._preferences=null,this._refs=new d.Manager,this._cache=null,this._valids=null,this._invalids=null,this._flags={},this._rules=[],this._singleRules=new Map,this.$_terms={},this.$_temp={ruleset:null,whens:{}}}describe(){return s("function"==typeof m.describe,"Manifest functionality disabled"),m.describe(this)}allow(...e){return l.verifyFlat(e,"allow"),this._values(e,"_valids")}alter(e){s(e&&"object"==typeof e&&!Array.isArray(e),"Invalid targets argument"),s(!this._inRuleset(),"Cannot set alterations inside a ruleset");const t=this.clone();t.$_terms.alterations=t.$_terms.alterations||[];for(const r in e){const n=e[r];s("function"==typeof n,"Alteration adjuster for",r,"must be a function"),t.$_terms.alterations.push({target:r,adjuster:n})}return t.$_temp.ruleset=!1,t}artifact(e){return s(void 0!==e,"Artifact cannot be undefined"),s(!this._cache,"Cannot set an artifact with a rule cache"),this.$_setFlag("artifact",e)}cast(e){return s(!1===e||"string"==typeof e,"Invalid to value"),s(!1===e||this._definition.cast[e],"Type",this.type,"does not support casting to",e),this.$_setFlag("cast",!1===e?void 0:e)}default(e,t){return this._default("default",e,t)}description(e){return s(e&&"string"==typeof e,"Description must be a non-empty string"),this.$_setFlag("description",e)}empty(e){const t=this.clone();return void 0!==e&&(e=t.$_compile(e,{override:!1})),t.$_setFlag("empty",e,{clone:!1})}error(e){return s(e,"Missing error"),s(e instanceof Error||"function"==typeof e,"Must provide a valid Error object or a function"),this.$_setFlag("error",e)}example(e,t={}){return s(void 0!==e,"Missing example"),l.assertOptions(t,["override"]),this._inner("examples",e,{single:!0,override:t.override})}external(e,t){return"object"==typeof e&&(s(!t,"Cannot combine options with description"),t=e.description,e=e.method),s("function"==typeof e,"Method must be a function"),s(void 0===t||t&&"string"==typeof t,"Description must be a non-empty string"),this._inner("externals",{method:e,description:t},{single:!0})}failover(e,t){return this._default("failover",e,t)}forbidden(){return this.presence("forbidden")}id(e){return e?(s("string"==typeof e,"id must be a non-empty string"),s(/^[^\.]+$/.test(e),"id cannot contain period character"),this.$_setFlag("id",e)):this.$_setFlag("id",void 0)}invalid(...e){return this._values(e,"_invalids")}label(e){return s(e&&"string"==typeof e,"Label name must be a non-empty string"),this.$_setFlag("label",e)}meta(e){return s(void 0!==e,"Meta cannot be undefined"),this._inner("metas",e,{single:!0})}note(...e){s(e.length,"Missing notes");for(const t of e)s(t&&"string"==typeof t,"Notes must be non-empty strings");return this._inner("notes",e)}only(e=!0){return s("boolean"==typeof e,"Invalid mode:",e),this.$_setFlag("only",e)}optional(){return this.presence("optional")}prefs(e){s(e,"Missing preferences"),s(void 0===e.context,"Cannot override context"),s(void 0===e.externals,"Cannot override externals"),s(void 0===e.warnings,"Cannot override warnings"),s(void 0===e.debug,"Cannot override debug"),l.checkPreferences(e);const t=this.clone();return t._preferences=l.preferences(t._preferences,e),t}presence(e){return s(["optional","required","forbidden"].includes(e),"Unknown presence mode",e),this.$_setFlag("presence",e)}raw(e=!0){return this.$_setFlag("result",e?"raw":void 0)}result(e){return s(["raw","strip"].includes(e),"Unknown result mode",e),this.$_setFlag("result",e)}required(){return this.presence("required")}strict(e){const t=this.clone(),r=void 0!==e&&!e;return t._preferences=l.preferences(t._preferences,{convert:r}),t}strip(e=!0){return this.$_setFlag("result",e?"strip":void 0)}tag(...e){s(e.length,"Missing tags");for(const t of e)s(t&&"string"==typeof t,"Tags must be non-empty strings");return this._inner("tags",e)}unit(e){return s(e&&"string"==typeof e,"Unit name must be a non-empty string"),this.$_setFlag("unit",e)}valid(...e){l.verifyFlat(e,"valid");const t=this.allow(...e);return t.$_setFlag("only",!!t._valids,{clone:!1}),t}when(e,t){const r=this.clone();r.$_terms.whens||(r.$_terms.whens=[]);const n=c.when(r,e,t);if(!["any","link"].includes(r.type)){const e=n.is?[n]:n.switch;for(const t of e)s(!t.then||"any"===t.then.type||t.then.type===r.type,"Cannot combine",r.type,"with",t.then&&t.then.type),s(!t.otherwise||"any"===t.otherwise.type||t.otherwise.type===r.type,"Cannot combine",r.type,"with",t.otherwise&&t.otherwise.type)}return r.$_terms.whens.push(n),r.$_mutateRebuild()}cache(e){s(!this._inRuleset(),"Cannot set caching inside a ruleset"),s(!this._cache,"Cannot override schema cache"),s(void 0===this._flags.artifact,"Cannot cache a rule with an artifact");const t=this.clone();return t._cache=e||i.provider.provision(),t.$_temp.ruleset=!1,t}clone(){const e=Object.create(Object.getPrototypeOf(this));return this._assign(e)}concat(e){s(l.isSchema(e),"Invalid schema object"),s("any"===this.type||"any"===e.type||e.type===this.type,"Cannot merge type",this.type,"with another type:",e.type),s(!this._inRuleset(),"Cannot concatenate onto a schema with open ruleset"),s(!e._inRuleset(),"Cannot concatenate a schema with open ruleset");let t=this.clone();if("any"===this.type&&"any"!==e.type){const r=e.clone();for(const e of Object.keys(t))"type"!==e&&(r[e]=t[e]);t=r}t._ids.concat(e._ids),t._refs.register(e,d.toSibling),t._preferences=t._preferences?l.preferences(t._preferences,e._preferences):e._preferences,t._valids=b.merge(t._valids,e._valids,e._invalids),t._invalids=b.merge(t._invalids,e._invalids,e._valids);for(const r of e._singleRules.keys())t._singleRules.has(r)&&(t._rules=t._rules.filter(e=>e.keep||e.name!==r),t._singleRules.delete(r));for(const r of e._rules)e._definition.rules[r.method].multi||t._singleRules.set(r.name,r),t._rules.push(r);if(t._flags.empty&&e._flags.empty){t._flags.empty=t._flags.empty.concat(e._flags.empty);const r=Object.assign({},e._flags);delete r.empty,o(t._flags,r)}else if(e._flags.empty){t._flags.empty=e._flags.empty;const r=Object.assign({},e._flags);delete r.empty,o(t._flags,r)}else o(t._flags,e._flags);for(const r in e.$_terms){const s=e.$_terms[r];s?t.$_terms[r]?t.$_terms[r]=t.$_terms[r].concat(s):t.$_terms[r]=s.slice():t.$_terms[r]||(t.$_terms[r]=s)}return this.$_root._tracer&&this.$_root._tracer._combine(t,[this,e]),t.$_mutateRebuild()}extend(e){return s(!e.base,"Cannot extend type with another base"),f.type(this,e)}extract(e){return e=Array.isArray(e)?e:e.split("."),this._ids.reach(e)}fork(e,t){s(!this._inRuleset(),"Cannot fork inside a ruleset");let r=this;for(let s of[].concat(e))s=Array.isArray(s)?s:s.split("."),r=r._ids.fork(s,t,r);return r.$_temp.ruleset=!1,r}rule(e){const t=this._definition;l.assertOptions(e,Object.keys(t.modifiers)),s(!1!==this.$_temp.ruleset,"Cannot apply rules to empty ruleset or the last rule added does not support rule properties");const r=null===this.$_temp.ruleset?this._rules.length-1:this.$_temp.ruleset;s(r>=0&&r<this._rules.length,"Cannot apply rules to empty ruleset");const a=this.clone();for(let o=r;o<a._rules.length;++o){const r=a._rules[o],i=n(r);for(const n in e)t.modifiers[n](i,e[n]),s(i.name===r.name,"Cannot change rule name");a._rules[o]=i,a._singleRules.get(i.name)===r&&a._singleRules.set(i.name,i)}return a.$_temp.ruleset=!1,a.$_mutateRebuild()}get ruleset(){s(!this._inRuleset(),"Cannot start a new ruleset without closing the previous one");const e=this.clone();return e.$_temp.ruleset=e._rules.length,e}get $(){return this.ruleset}tailor(e){e=[].concat(e),s(!this._inRuleset(),"Cannot tailor inside a ruleset");let t=this;if(this.$_terms.alterations)for(const{target:r,adjuster:n}of this.$_terms.alterations)e.includes(r)&&(t=n(t),s(l.isSchema(t),"Alteration adjuster for",r,"failed to return a schema object"));return t=t.$_modify({each:t=>t.tailor(e),ref:!1}),t.$_temp.ruleset=!1,t.$_mutateRebuild()}tracer(){return g.location?g.location(this):this}validate(e,t){return y.entry(e,this,t)}validateAsync(e,t){return y.entryAsync(e,this,t)}$_addRule(e){"string"==typeof e&&(e={name:e}),s(e&&"object"==typeof e,"Invalid options"),s(e.name&&"string"==typeof e.name,"Invalid rule name");for(const t in e)s("_"!==t[0],"Cannot set private rule properties");const t=Object.assign({},e);t._resolve=[],t.method=t.method||t.name;const r=this._definition.rules[t.method],n=t.args;s(r,"Unknown rule",t.method);const a=this.clone();if(n){s(1===Object.keys(n).length||Object.keys(n).length===this._definition.rules[t.name].args.length,"Invalid rule definition for",this.type,t.name);for(const e in n){let o=n[e];if(void 0!==o){if(r.argsByName){const i=r.argsByName.get(e);if(i.ref&&l.isResolvable(o))t._resolve.push(e),a.$_mutateRegister(o);else if(i.normalize&&(o=i.normalize(o),n[e]=o),i.assert){const t=l.validateArg(o,e,i);s(!t,t,"or reference")}}n[e]=o}else delete n[e]}}return r.multi||(a._ruleRemove(t.name,{clone:!1}),a._singleRules.set(t.name,t)),!1===a.$_temp.ruleset&&(a.$_temp.ruleset=null),r.priority?a._rules.unshift(t):a._rules.push(t),a}$_compile(e,t){return c.schema(this.$_root,e,t)}$_createError(e,t,r,s,n,a={}){const o=!1!==a.flags?this._flags:{},i=a.messages?h.merge(this._definition.messages,a.messages):this._definition.messages;return new u.Report(e,t,r,o,i,s,n)}$_getFlag(e){return this._flags[e]}$_getRule(e){return this._singleRules.get(e)}$_mapLabels(e){return e=Array.isArray(e)?e:e.split("."),this._ids.labels(e)}$_match(e,t,r,s){(r=Object.assign({},r)).abortEarly=!0,r._externals=!1,t.snapshot();const n=!y.validate(e,this,t,r,s).errors;return t.restore(),n}$_modify(e){return l.assertOptions(e,["each","once","ref","schema"]),p.schema(this,e)||this}$_mutateRebuild(){s(!this._inRuleset(),"Cannot add this rule inside a ruleset"),this._refs.reset(),this._ids.reset();return this.$_modify({each:(e,{source:t,name:r,path:s,key:n})=>{const a=this._definition[t][r]&&this._definition[t][r].register;!1!==a&&this.$_mutateRegister(e,{family:a,key:n})}}),this._definition.rebuild&&this._definition.rebuild(this),this.$_temp.ruleset=!1,this}$_mutateRegister(e,{family:t,key:r}={}){this._refs.register(e,t),this._ids.register(e,{key:r})}$_property(e){return this._definition.properties[e]}$_reach(e){return this._ids.reach(e)}$_rootReferences(){return this._refs.roots()}$_setFlag(e,t,r={}){s("_"===e[0]||!this._inRuleset(),"Cannot set flag inside a ruleset");const n=this._definition.flags[e]||{};if(a(t,n.default)&&(t=void 0),a(t,this._flags[e]))return this;const o=!1!==r.clone?this.clone():this;return void 0!==t?(o._flags[e]=t,o.$_mutateRegister(t)):delete o._flags[e],"_"!==e[0]&&(o.$_temp.ruleset=!1),o}$_parent(e,...t){return this[e][l.symbols.parent].call(this,...t)}$_validate(e,t,r){return y.validate(e,this,t,r)}_assign(e){e.type=this.type,e.$_root=this.$_root,e.$_temp=Object.assign({},this.$_temp),e.$_temp.whens={},e._ids=this._ids.clone(),e._preferences=this._preferences,e._valids=this._valids&&this._valids.clone(),e._invalids=this._invalids&&this._invalids.clone(),e._rules=this._rules.slice(),e._singleRules=n(this._singleRules,{shallow:!0}),e._refs=this._refs.clone(),e._flags=Object.assign({},this._flags),e._cache=null,e.$_terms={};for(const t in this.$_terms)e.$_terms[t]=this.$_terms[t]?this.$_terms[t].slice():null;e.$_super={};for(const t in this.$_super)e.$_super[t]=this._super[t].bind(e);return e}_bare(){const e=this.clone();e._reset();const t=e._definition.terms;for(const r in t){const s=t[r];e.$_terms[r]=s.init}return e.$_mutateRebuild()}_default(e,t,r={}){l.assertOptions(r,"literal"),s(void 0!==t,"Missing",e,"value"),s("function"==typeof t||!r.literal,"Only function value supports literal option"),"function"==typeof t&&r.literal&&(t={[l.symbols.literal]:!0,literal:t});return this.$_setFlag(e,t)}_generate(e,t,r){if(!this.$_terms.whens)return{schema:this};const s=[],n=[];for(let a=0;a<this.$_terms.whens.length;++a){const o=this.$_terms.whens[a];if(o.concat){s.push(o.concat),n.push("".concat(a,".concat"));continue}const i=o.ref?o.ref.resolve(e,t,r):e,l=o.is?[o]:o.switch,c=n.length;for(let c=0;c<l.length;++c){const{is:u,then:f,otherwise:m}=l[c],h="".concat(a).concat(o.switch?"."+c:"");if(u.$_match(i,t.nest(u,"".concat(h,".is")),r)){if(f){const a=t.localize([...t.path,"".concat(h,".then")],t.ancestors,t.schemas),{schema:o,id:i}=f._generate(e,a,r);s.push(o),n.push("".concat(h,".then").concat(i?"(".concat(i,")"):""));break}}else if(m){const a=t.localize([...t.path,"".concat(h,".otherwise")],t.ancestors,t.schemas),{schema:o,id:i}=m._generate(e,a,r);s.push(o),n.push("".concat(h,".otherwise").concat(i?"(".concat(i,")"):""));break}}if(o.break&&n.length>c)break}const a=n.join(", ");if(t.mainstay.tracer.debug(t,"rule","when",a),!a)return{schema:this};if(!t.mainstay.tracer.active&&this.$_temp.whens[a])return{schema:this.$_temp.whens[a],id:a};let o=this;this._definition.generate&&(o=this._definition.generate(this,e,t,r));for(const e of s)o=o.concat(e);return this.$_root._tracer&&this.$_root._tracer._combine(o,[this,...s]),this.$_temp.whens[a]=o,{schema:o,id:a}}_inner(e,t,r={}){s(!this._inRuleset(),"Cannot set ".concat(e," inside a ruleset"));const n=this.clone();return n.$_terms[e]&&!r.override||(n.$_terms[e]=[]),r.single?n.$_terms[e].push(t):n.$_terms[e].push(...t),n.$_temp.ruleset=!1,n}_inRuleset(){return null!==this.$_temp.ruleset&&!1!==this.$_temp.ruleset}_ruleRemove(e,t={}){if(!this._singleRules.has(e))return this;const r=!1!==t.clone?this.clone():this;r._singleRules.delete(e);const s=[];for(let t=0;t<r._rules.length;++t){const n=r._rules[t];n.name!==e||n.keep?s.push(n):r._inRuleset()&&t<r.$_temp.ruleset&&--r.$_temp.ruleset}return r._rules=s,r}_values(e,t){l.verifyFlat(e,t.slice(1,-1));const r=this.clone(),n=e[0]===l.symbols.override;if(n&&(e=e.slice(1)),!r[t]&&e.length?r[t]=new b:n&&(r[t]=e.length?new b:null,r.$_mutateRebuild()),!r[t])return r;n&&r[t].override();for(const n of e){s(void 0!==n,"Cannot call allow/valid/invalid with undefined"),s(n!==l.symbols.override,"Override must be the first value");const e="_invalids"===t?"_valids":"_invalids";r[e]&&(r[e].remove(n),r[e].length||(s("_valids"===t||!r._flags.only,"Setting invalid value",n,"leaves schema rejecting all values due to previous valid rule"),r[e]=null)),r[t].add(n,r._refs)}return r}}};v.Base.prototype[l.symbols.any]={version:l.version,compile:c.compile,root:"$_root"},v.Base.prototype.isImmutable=!0,v.Base.prototype.deny=v.Base.prototype.invalid,v.Base.prototype.disallow=v.Base.prototype.invalid,v.Base.prototype.equal=v.Base.prototype.valid,v.Base.prototype.exist=v.Base.prototype.required,v.Base.prototype.not=v.Base.prototype.invalid,v.Base.prototype.options=v.Base.prototype.prefs,v.Base.prototype.preferences=v.Base.prototype.prefs,e.exports=new v.Base},function(e,t,r){"use strict";function s(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,s)}return r}function n(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?s(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):s(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const o=r(0),i=r(1),l=r(5),c={};t.Ids=c.Ids=class{constructor(){this._byId=new Map,this._byKey=new Map,this._schemaChain=!1}clone(){const e=new c.Ids;return e._byId=new Map(this._byId),e._byKey=new Map(this._byKey),e._schemaChain=this._schemaChain,e}concat(e){e._schemaChain&&(this._schemaChain=!0);for(const[t,r]of e._byId.entries())o(!this._byKey.has(t),"Schema id conflicts with existing key:",t),this._byId.set(t,r);for(const[t,r]of e._byKey.entries())o(!this._byId.has(t),"Schema key conflicts with existing id:",t),this._byKey.set(t,r)}fork(e,t,r){const s=this._collect(e);s.push({schema:r});const n=s.shift();let a={id:n.id,schema:t(n.schema)};o(i.isSchema(a.schema),"adjuster function failed to return a joi schema type");for(const e of s)a={id:e.id,schema:c.fork(e.schema,a.id,a.schema)};return a.schema}labels(e,t=[]){const r=e[0],s=this._get(r);if(!s)return[...t,...e].join(".");const n=e.slice(1);return t=[...t,s.schema._flags.label||r],n.length?s.schema._ids.labels(n,t):t.join(".")}reach(e,t=[]){const r=e[0],s=this._get(r);o(s,"Schema does not contain path",[...t,...e].join("."));const n=e.slice(1);return n.length?s.schema._ids.reach(n,[...t,r]):s.schema}register(e,{key:t}={}){if(!e||!i.isSchema(e))return;(e.$_property("schemaChain")||e._ids._schemaChain)&&(this._schemaChain=!0);const r=e._flags.id;if(r){const t=this._byId.get(r);o(!t||t.schema===e,"Cannot add different schemas with the same id:",r),o(!this._byKey.has(r),"Schema id conflicts with existing key:",r),this._byId.set(r,{schema:e,id:r})}t&&(o(!this._byKey.has(t),"Schema already contains key:",t),o(!this._byId.has(t),"Schema key conflicts with existing id:",t),this._byKey.set(t,{schema:e,id:t}))}reset(){this._byId=new Map,this._byKey=new Map,this._schemaChain=!1}_collect(e,t=[],r=[]){const s=e[0],n=this._get(s);o(n,"Schema does not contain path",[...t,...e].join(".")),r=[n,...r];const a=e.slice(1);return a.length?n.schema._ids._collect(a,[...t,s],r):r}_get(e){return this._byId.get(e)||this._byKey.get(e)}},c.fork=function(e,r,s){const n=t.schema(e,{each:(e,{key:t})=>{if(r===(e._flags.id||t))return s},ref:!1});return n?n.$_mutateRebuild():e},t.schema=function(e,t){let r;for(const s in e._flags){if("_"===s[0])continue;const n=c.scan(e._flags[s],{source:"flags",name:s},t);void 0!==n&&(r=r||e.clone(),r._flags[s]=n)}for(let s=0;s<e._rules.length;++s){const n=e._rules[s],a=c.scan(n.args,{source:"rules",name:n.name},t);if(void 0!==a){r=r||e.clone();const t=Object.assign({},n);t.args=a,r._rules[s]=t;r._singleRules.get(n.name)===n&&r._singleRules.set(n.name,t)}}for(const s in e.$_terms){if("_"===s[0])continue;const n=c.scan(e.$_terms[s],{source:"terms",name:s},t);void 0!==n&&(r=r||e.clone(),r.$_terms[s]=n)}return r},c.scan=function(e,t,r,s,a){const o=s||[];if(null===e||"object"!=typeof e)return;let u;if(Array.isArray(e)){for(let s=0;s<e.length;++s){const n="terms"===t.source&&"keys"===t.name&&e[s].key,a=c.scan(e[s],t,r,[s,...o],n);void 0!==a&&(u=u||e.slice(),u[s]=a)}return u}if(!1!==r.schema&&i.isSchema(e)||!1!==r.ref&&l.isRef(e)){const s=r.each(e,n(n({},t),{},{path:o,key:a}));if(s===e)return;return s}for(const s in e){if("_"===s[0])continue;const n=c.scan(e[s],t,r,[s,...o],a);void 0!==n&&(u=u||Object.assign({},e),u[s]=n)}return u}},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(37),o=r(6),i=r(1),l=r(4),c=r(38),u={result:Symbol("result")};t.entry=function(e,t,r){let n=i.defaults;r&&(s(void 0===r.warnings,"Cannot override warnings preference in synchronous validation"),s(void 0===r.artifacts,"Cannot override artifacts preference in synchronous validation"),n=i.preferences(i.defaults,r));const a=u.entry(e,t,n);s(!a.mainstay.externals.length,"Schema with external rules must use validateAsync()");const o={value:a.value};return a.error&&(o.error=a.error),a.mainstay.warnings.length&&(o.warning=l.details(a.mainstay.warnings)),a.mainstay.debug&&(o.debug=a.mainstay.debug),a.mainstay.artifacts&&(o.artifacts=a.mainstay.artifacts),o},t.entryAsync=async function(e,t,r){let s=i.defaults;r&&(s=i.preferences(i.defaults,r));const n=u.entry(e,t,s),a=n.mainstay;if(n.error)throw a.debug&&(n.error.debug=a.debug),n.error;if(a.externals.length){let e=n.value;for(const{method:t,path:s,label:n}of a.externals){let a,i,l=e;s.length&&(a=s[s.length-1],i=o(e,s.slice(0,-1)),l=i[a]);try{const s=await t(l,{prefs:r});if(void 0===s||s===l)continue;i?i[a]=s:e=s}catch(e){throw e.message+=" (".concat(n,")"),e}}n.value=e}if(!s.warnings&&!s.debug&&!s.artifacts)return n.value;const c={value:n.value};return a.warnings.length&&(c.warning=l.details(a.warnings)),a.debug&&(c.debug=a.debug),a.artifacts&&(c.artifacts=a.artifacts),c},u.entry=function(e,r,s){const{tracer:n,cleanup:a}=u.tracer(r,s),o={externals:[],warnings:[],tracer:n,debug:s.debug?[]:null,links:r._ids._schemaChain?new Map:null},i=r._ids._schemaChain?[{schema:r}]:null,f=new c([],[],{mainstay:o,schemas:i}),m=t.validate(e,r,f,s);a&&r.$_root.untrace();const h=l.process(m.errors,e,s);return{value:m.value,error:h,mainstay:o}},u.tracer=function(e,t){return e.$_root._tracer?{tracer:e.$_root._tracer._register(e)}:t.debug?(s(e.$_root.trace,"Debug mode not supported"),{tracer:e.$_root.trace()._register(e),cleanup:!0}):{tracer:u.ignore}},t.validate=function(e,t,r,s,n={}){if(t.$_terms.whens&&(t=t._generate(e,r,s).schema),t._preferences&&(s=u.prefs(t,s)),t._cache&&s.cache){const s=t._cache.get(e);if(r.mainstay.tracer.debug(r,"validate","cached",!!s),s)return s}const a=(n,a,o)=>t.$_createError(n,e,a,o||r,s),o={original:e,prefs:s,schema:t,state:r,error:a,errorsArray:u.errorsArray,warn:(e,t,s)=>r.mainstay.warnings.push(a(e,t,s)),message:(n,a)=>t.$_createError("custom",e,a,r,s,{messages:n})};r.mainstay.tracer.entry(t,r);const l=t._definition;if(l.prepare&&void 0!==e&&s.convert){const t=l.prepare(e,o);if(t){if(r.mainstay.tracer.value(r,"prepare",e,t.value),t.errors)return u.finalize(t.value,[].concat(t.errors),o);e=t.value}}if(l.coerce&&void 0!==e&&s.convert&&(!l.coerce.from||l.coerce.from.includes(typeof e))){const t=l.coerce.method(e,o);if(t){if(r.mainstay.tracer.value(r,"coerced",e,t.value),t.errors)return u.finalize(t.value,[].concat(t.errors),o);e=t.value}}const c=t._flags.empty;c&&c.$_match(u.trim(e,t),r.nest(c),i.defaults)&&(r.mainstay.tracer.value(r,"empty",e,void 0),e=void 0);const f=n.presence||t._flags.presence||(t._flags._endedSwitch?null:s.presence);if(void 0===e){if("forbidden"===f)return u.finalize(e,null,o);if("required"===f)return u.finalize(e,[t.$_createError("any.required",e,null,r,s)],o);if("optional"===f){if(t._flags.default!==i.symbols.deepDefault)return u.finalize(e,null,o);r.mainstay.tracer.value(r,"default",e,{}),e={}}}else if("forbidden"===f)return u.finalize(e,[t.$_createError("any.unknown",e,null,r,s)],o);const m=[];if(t._valids){const n=t._valids.get(e,r,s,t._flags.insensitive);if(n)return s.convert&&(r.mainstay.tracer.value(r,"valids",e,n.value),e=n.value),r.mainstay.tracer.filter(t,r,"valid",n),u.finalize(e,null,o);if(t._flags.only){const n=t.$_createError("any.only",e,{valids:t._valids.values({display:!0})},r,s);if(s.abortEarly)return u.finalize(e,[n],o);m.push(n)}}if(t._invalids){const n=t._invalids.get(e,r,s,t._flags.insensitive);if(n){r.mainstay.tracer.filter(t,r,"invalid",n);const a=t.$_createError("any.invalid",e,{invalids:t._invalids.values({display:!0})},r,s);if(s.abortEarly)return u.finalize(e,[a],o);m.push(a)}}if(l.validate){const t=l.validate(e,o);if(t&&(r.mainstay.tracer.value(r,"base",e,t.value),e=t.value,t.errors)){if(!Array.isArray(t.errors))return m.push(t.errors),u.finalize(e,m,o);if(t.errors.length)return m.push(...t.errors),u.finalize(e,m,o)}}return t._rules.length?u.rules(e,m,o):u.finalize(e,m,o)},u.rules=function(e,t,r){const{schema:s,state:n,prefs:a}=r;for(const o of s._rules){const l=s._definition.rules[o.method];if(l.convert&&a.convert){n.mainstay.tracer.log(s,n,"rule",o.name,"full");continue}let c,f=o.args;if(o._resolve.length){f=Object.assign({},f);for(const t of o._resolve){const r=l.argsByName.get(t),o=f[t].resolve(e,n,a),u=r.normalize?r.normalize(o):o,m=i.validateArg(u,null,r);if(m){c=s.$_createError("any.ref",o,{arg:t,ref:f[t],reason:m},n,a);break}f[t]=u}}c=c||l.validate(e,r,f,o);const m=u.rule(c,o);if(m.errors){if(n.mainstay.tracer.log(s,n,"rule",o.name,"error"),o.warn){n.mainstay.warnings.push(...m.errors);continue}if(a.abortEarly)return u.finalize(e,m.errors,r);t.push(...m.errors)}else n.mainstay.tracer.log(s,n,"rule",o.name,"pass"),n.mainstay.tracer.value(n,"rule",e,m.value,o.name),e=m.value}return u.finalize(e,t,r)},u.rule=function(e,t){return e instanceof l.Report?(u.error(e,t),{errors:[e],value:null}):Array.isArray(e)&&e[i.symbols.errors]?(e.forEach(e=>u.error(e,t)),{errors:e,value:null}):{errors:null,value:e}},u.error=function(e,t){return t.message&&e._setTemplate(t.message),e},u.finalize=function(e,t,r){t=t||[];const{schema:n,state:a,prefs:o}=r;if(t.length){const s=u.default("failover",void 0,t,r);void 0!==s&&(a.mainstay.tracer.value(a,"failover",e,s),e=s,t=[])}if(t.length&&n._flags.error)if("function"==typeof n._flags.error){t=n._flags.error(t),Array.isArray(t)||(t=[t]);for(const e of t)s(e instanceof Error||e instanceof l.Report,"error() must return an Error object")}else t=[n._flags.error];if(void 0===e){const s=u.default("default",e,t,r);a.mainstay.tracer.value(a,"default",e,s),e=s}if(n._flags.cast&&void 0!==e){const t=n._definition.cast[n._flags.cast];if(t.from(e)){const s=t.to(e,r);a.mainstay.tracer.value(a,"cast",e,s,n._flags.cast),e=s}}if(n.$_terms.externals&&o.externals&&!1!==o._externals)for(const{method:e}of n.$_terms.externals)a.mainstay.externals.push({method:e,path:a.path,label:l.label(n._flags,a,o)});const i={value:e,errors:t.length?t:null};return n._flags.result&&(i.value="strip"===n._flags.result?void 0:r.original,a.mainstay.tracer.value(a,n._flags.result,e,i.value),a.shadow(e,n._flags.result)),n._cache&&!1!==o.cache&&!n._refs.length&&n._cache.set(r.original,i),void 0===e||i.errors||void 0===n._flags.artifact||(a.mainstay.artifacts=a.mainstay.artifacts||new Map,a.mainstay.artifacts.has(n._flags.artifact)||a.mainstay.artifacts.set(n._flags.artifact,[]),a.mainstay.artifacts.get(n._flags.artifact).push(a.path)),i},u.prefs=function(e,t){const r=t===i.defaults;return r&&e._preferences[i.symbols.prefs]?e._preferences[i.symbols.prefs]:(t=i.preferences(t,e._preferences),r&&(e._preferences[i.symbols.prefs]=t),t)},u.default=function(e,t,r,s){const{schema:a,state:o,prefs:l}=s,c=a._flags[e];if(l.noDefaults||void 0===c)return t;if(o.mainstay.tracer.log(a,o,"rule",e,"full"),!c)return c;if("function"==typeof c){const t=c.length?[n(o.ancestors[0]),s]:[];try{return c(...t)}catch(t){return void r.push(a.$_createError("any.".concat(e),null,{error:t},o,l))}}return"object"!=typeof c?c:c[i.symbols.literal]?c.literal:i.isResolvable(c)?c.resolve(t,o,l):n(c)},u.trim=function(e,t){if("string"!=typeof e)return e;const r=t.$_getRule("trim");return r&&r.args.enabled?e.trim():e},u.ignore={active:!1,debug:a,entry:a,filter:a,log:a,resolve:a,value:a},u.errorsArray=function(){const e=[];return e[i.symbols.errors]=!0,e}},function(e,t,r){"use strict";e.exports=function(){}},function(e,t,r){"use strict";const s=r(2),n=r(6),a=r(1),o={value:Symbol("value")};e.exports=o.State=class{constructor(e,t,r){this.path=e,this.ancestors=t,this.mainstay=r.mainstay,this.schemas=r.schemas,this.debug=null}localize(e,t=null,r=null){const s=new o.State(e,t,this);return r&&s.schemas&&(s.schemas=[o.schemas(r),...s.schemas]),s}nest(e,t){const r=new o.State(this.path,this.ancestors,this);return r.schemas=r.schemas&&[o.schemas(e),...r.schemas],r.debug=t,r}shadow(e,t){this.mainstay.shadow=this.mainstay.shadow||new o.Shadow,this.mainstay.shadow.set(this.path,e,t)}snapshot(){this.mainstay.shadow&&(this._snapshot=s(this.mainstay.shadow.node(this.path)))}restore(){this.mainstay.shadow&&(this.mainstay.shadow.override(this.path,this._snapshot),this._snapshot=void 0)}},o.schemas=function(e){return a.isSchema(e)?{schema:e}:e},o.Shadow=class{constructor(){this._values=null}set(e,t,r){if(!e.length)return;if("strip"===r&&"number"==typeof e[e.length-1])return;this._values=this._values||new Map;let s=this._values;for(let t=0;t<e.length;++t){const r=e[t];let n=s.get(r);n||(n=new Map,s.set(r,n)),s=n}s[o.value]=t}get(e){const t=this.node(e);if(t)return t[o.value]}node(e){if(this._values)return n(this._values,e,{iterables:!0})}override(e,t){if(!this._values)return;const r=e.slice(0,-1),s=e[e.length-1],a=n(this._values,r,{iterables:!0});t?a.set(s,t):a&&a.delete(s)}}},function(e,t,r){"use strict";const s=r(0),n=r(10),a=r(6),o=r(3),i=r(1),l=r(8),c={};e.exports=o.extend({type:"array",flags:{single:{default:!1},sparse:{default:!1}},terms:{items:{init:[],manifest:"schema"},ordered:{init:[],manifest:"schema"},_exclusions:{init:[]},_inclusions:{init:[]},_requireds:{init:[]}},coerce:{from:"object",method(e,{schema:t,state:r,prefs:s}){if(!Array.isArray(e))return;const n=t.$_getRule("sort");return n?c.sort(t,e,n.args.options,r,s):void 0}},validate(e,{schema:t,error:r}){if(!Array.isArray(e)){if(t._flags.single){const t=[e];return t[i.symbols.arraySingle]=!0,{value:t}}return{errors:r("array.base")}}if(t.$_getRule("items")||t.$_terms.externals)return{value:e.slice()}},rules:{has:{method(e){e=this.$_compile(e,{appendPath:!0});const t=this.$_addRule({name:"has",args:{schema:e}});return t.$_mutateRegister(e),t},validate(e,{state:t,prefs:r,error:s},{schema:n}){const a=[e,...t.ancestors];for(let s=0;s<e.length;++s){const o=t.localize([...t.path,s],a,n);if(n.$_match(e[s],o,r))return e}const o=n._flags.label;return o?s("array.hasKnown",{patternLabel:o}):s("array.hasUnknown",null)},multi:!0},items:{method(...e){i.verifyFlat(e,"items");const t=this.$_addRule("items");for(let r=0;r<e.length;++r){const s=i.tryWithPath(()=>this.$_compile(e[r]),r,{append:!0});t.$_terms.items.push(s)}return t.$_mutateRebuild()},validate(e,{schema:t,error:r,state:s,prefs:n,errorsArray:a}){const o=t.$_terms._requireds.slice(),l=t.$_terms.ordered.slice(),u=[...t.$_terms._inclusions,...o],f=!e[i.symbols.arraySingle];delete e[i.symbols.arraySingle];const m=a();let h=e.length;for(let a=0;a<h;++a){const i=e[a];let p=!1,d=!1;const g=f?a:new Number(a),y=[...s.path,g];if(!t._flags.sparse&&void 0===i){if(m.push(r("array.sparse",{key:g,path:y,pos:a,value:void 0},s.localize(y))),n.abortEarly)return m;l.shift();continue}const b=[e,...s.ancestors];for(const e of t.$_terms._exclusions)if(e.$_match(i,s.localize(y,b,e),n,{presence:"ignore"})){if(m.push(r("array.excludes",{pos:a,value:i},s.localize(y))),n.abortEarly)return m;p=!0,l.shift();break}if(p)continue;if(t.$_terms.ordered.length){if(l.length){const o=l.shift(),u=o.$_validate(i,s.localize(y,b,o),n);if(u.errors){if(m.push(...u.errors),n.abortEarly)return m}else if("strip"===o._flags.result)c.fastSplice(e,a),--a,--h;else{if(!t._flags.sparse&&void 0===u.value){if(m.push(r("array.sparse",{key:g,path:y,pos:a,value:void 0},s.localize(y))),n.abortEarly)return m;continue}e[a]=u.value}continue}if(!t.$_terms.items.length){if(m.push(r("array.orderedLength",{pos:a,limit:t.$_terms.ordered.length})),n.abortEarly)return m;break}}const v=[];let _=o.length;for(let l=0;l<_;++l){const u=s.localize(y,b,o[l]);u.snapshot();const f=o[l].$_validate(i,u,n);if(v[l]=f,!f.errors){if(e[a]=f.value,d=!0,c.fastSplice(o,l),--l,--_,!t._flags.sparse&&void 0===f.value&&(m.push(r("array.sparse",{key:g,path:y,pos:a,value:void 0},s.localize(y))),n.abortEarly))return m;break}u.restore()}if(d)continue;const w=n.stripUnknown&&!!n.stripUnknown.arrays||!1;_=u.length;for(const l of u){let u;const f=o.indexOf(l);if(-1!==f)u=v[f];else{const o=s.localize(y,b,l);if(o.snapshot(),u=l.$_validate(i,o,n),!u.errors){"strip"===l._flags.result?(c.fastSplice(e,a),--a,--h):t._flags.sparse||void 0!==u.value?e[a]=u.value:(m.push(r("array.sparse",{key:g,path:y,pos:a,value:void 0},s.localize(y))),p=!0),d=!0;break}o.restore()}if(1===_){if(w){c.fastSplice(e,a),--a,--h,d=!0;break}if(m.push(...u.errors),n.abortEarly)return m;p=!0;break}}if(!p&&(t.$_terms._inclusions.length&&!d)){if(w){c.fastSplice(e,a),--a,--h;continue}if(m.push(r("array.includes",{pos:a,value:i},s.localize(y))),n.abortEarly)return m}}return o.length&&c.fillMissedErrors(t,m,o,e,s,n),l.length&&c.fillOrderedErrors(t,m,l,e,s,n),m.length?m:e},priority:!0,manifest:!1},length:{method(e){return this.$_addRule({name:"length",args:{limit:e},operator:"="})},validate:(e,t,{limit:r},{name:s,operator:n,args:a})=>i.compare(e.length,r,n)?e:t.error("array."+s,{limit:a.limit,value:e}),args:[{name:"limit",ref:!0,assert:i.limit,message:"must be a positive integer"}]},max:{method(e){return this.$_addRule({name:"max",method:"length",args:{limit:e},operator:"<="})}},min:{method(e){return this.$_addRule({name:"min",method:"length",args:{limit:e},operator:">="})}},ordered:{method(...e){i.verifyFlat(e,"ordered");const t=this.$_addRule("items");for(let r=0;r<e.length;++r){const s=i.tryWithPath(()=>this.$_compile(e[r]),r,{append:!0});c.validateSingle(s,t),t.$_mutateRegister(s),t.$_terms.ordered.push(s)}return t.$_mutateRebuild()}},single:{method(e){const t=void 0===e||!!e;return s(!t||!this._flags._arrayItems,"Cannot specify single rule when array has array items"),this.$_setFlag("single",t)}},sort:{method(e={}){i.assertOptions(e,["by","order"]);const t={order:e.order||"ascending"};return e.by&&(t.by=l.ref(e.by,{ancestor:0}),s(!t.by.ancestor,"Cannot sort by ancestor")),this.$_addRule({name:"sort",args:{options:t}})},validate(e,{error:t,state:r,prefs:s,schema:n},{options:a}){const{value:o,errors:i}=c.sort(n,e,a,r,s);if(i)return i;for(let r=0;r<e.length;++r)if(e[r]!==o[r])return t("array.sort",{order:a.order,by:a.by?a.by.key:"value"});return e},convert:!0},sparse:{method(e){const t=void 0===e||!!e;if(this._flags.sparse===t)return this;return(t?this.clone():this.$_addRule("items")).$_setFlag("sparse",t,{clone:!1})}},unique:{method(e,t={}){s(!e||"function"==typeof e||"string"==typeof e,"comparator must be a function or a string"),i.assertOptions(t,["ignoreUndefined","separator"]);const r={name:"unique",args:{options:t,comparator:e}};if(e)if("string"==typeof e){const s=i.default(t.separator,".");r.path=s?e.split(s):[e]}else r.comparator=e;return this.$_addRule(r)},validate(e,{state:t,error:r,schema:o},{comparator:i,options:l},{comparator:c,path:u}){const f={string:Object.create(null),number:Object.create(null),undefined:Object.create(null),boolean:Object.create(null),object:new Map,function:new Map,custom:new Map},m=c||n,h=l.ignoreUndefined;for(let n=0;n<e.length;++n){const o=u?a(e[n],u):e[n],l=c?f.custom:f[typeof o];if(s(l,"Failed to find unique map container for type",typeof o),l instanceof Map){const s=l.entries();let a;for(;!(a=s.next()).done;)if(m(a.value[0],o)){const s=t.localize([...t.path,n],[e,...t.ancestors]),o={pos:n,value:e[n],dupePos:a.value[1],dupeValue:e[a.value[1]]};return u&&(o.path=i),r("array.unique",o,s)}l.set(o,n)}else{if((!h||void 0!==o)&&void 0!==l[o]){const s={pos:n,value:e[n],dupePos:l[o],dupeValue:e[l[o]]};u&&(s.path=i);return r("array.unique",s,t.localize([...t.path,n],[e,...t.ancestors]))}l[o]=n}}return e},args:["comparator","options"],multi:!0}},cast:{set:{from:Array.isArray,to:(e,t)=>new Set(e)}},rebuild(e){e.$_terms._inclusions=[],e.$_terms._exclusions=[],e.$_terms._requireds=[];for(const t of e.$_terms.items)c.validateSingle(t,e),"required"===t._flags.presence?e.$_terms._requireds.push(t):"forbidden"===t._flags.presence?e.$_terms._exclusions.push(t):e.$_terms._inclusions.push(t);for(const t of e.$_terms.ordered)c.validateSingle(t,e)},manifest:{build:(e,t)=>(t.items&&(e=e.items(...t.items)),t.ordered&&(e=e.ordered(...t.ordered)),e)},messages:{"array.base":"{{#label}} must be an array","array.excludes":"{{#label}} contains an excluded value","array.hasKnown":"{{#label}} does not contain at least one required match for type {:#patternLabel}","array.hasUnknown":"{{#label}} does not contain at least one required match","array.includes":"{{#label}} does not match any of the allowed types","array.includesRequiredBoth":"{{#label}} does not contain {{#knownMisses}} and {{#unknownMisses}} other required value(s)","array.includesRequiredKnowns":"{{#label}} does not contain {{#knownMisses}}","array.includesRequiredUnknowns":"{{#label}} does not contain {{#unknownMisses}} required value(s)","array.length":"{{#label}} must contain {{#limit}} items","array.max":"{{#label}} must contain less than or equal to {{#limit}} items","array.min":"{{#label}} must contain at least {{#limit}} items","array.orderedLength":"{{#label}} must contain at most {{#limit}} items","array.sort":"{{#label}} must be sorted in {#order} order by {{#by}}","array.sort.mismatching":"{{#label}} cannot be sorted due to mismatching types","array.sort.unsupported":"{{#label}} cannot be sorted due to unsupported type {#type}","array.sparse":"{{#label}} must not be a sparse array item","array.unique":"{{#label}} contains a duplicate value"}}),c.fillMissedErrors=function(e,t,r,s,n,a){const o=[];let i=0;for(const e of r){const t=e._flags.label;t?o.push(t):++i}o.length?i?t.push(e.$_createError("array.includesRequiredBoth",s,{knownMisses:o,unknownMisses:i},n,a)):t.push(e.$_createError("array.includesRequiredKnowns",s,{knownMisses:o},n,a)):t.push(e.$_createError("array.includesRequiredUnknowns",s,{unknownMisses:i},n,a))},c.fillOrderedErrors=function(e,t,r,s,n,a){const o=[];for(const e of r)"required"===e._flags.presence&&o.push(e);o.length&&c.fillMissedErrors(e,t,o,s,n,a)},c.fastSplice=function(e,t){let r=t;for(;r<e.length;)e[r++]=e[r];--e.length},c.validateSingle=function(e,t){("array"===e.type||e._flags._arrayItems)&&(s(!t._flags.single,"Cannot specify array item with single rule enabled"),t.$_setFlag("_arrayItems",!0,{clone:!1}))},c.sort=function(e,t,r,s,n){const a="ascending"===r.order?1:-1,o=-1*a,i=a,l=(l,u)=>{let f=c.compare(l,u,o,i);if(null!==f)return f;if(r.by&&(l=r.by.resolve(l,s,n),u=r.by.resolve(u,s,n)),f=c.compare(l,u,o,i),null!==f)return f;const m=typeof l;if(m!==typeof u)throw e.$_createError("array.sort.mismatching",t,null,s,n);if("number"!==m&&"string"!==m)throw e.$_createError("array.sort.unsupported",t,{type:m},s,n);return"number"===m?(l-u)*a:l<u?o:i};try{return{value:t.slice().sort(l)}}catch(e){return{errors:e}}},c.compare=function(e,t,r,s){return e===t?0:void 0===e?1:void 0===t?-1:null===e?s:null===t?r:null}},function(e,t,r){"use strict";const s=r(0),n=r(3),a=r(1),o=r(21),i={isBool:function(e){return"boolean"==typeof e}};e.exports=n.extend({type:"boolean",flags:{sensitive:{default:!1}},terms:{falsy:{init:null,manifest:"values"},truthy:{init:null,manifest:"values"}},coerce(e,{schema:t}){if("boolean"!=typeof e){if("string"==typeof e){const r=t._flags.sensitive?e:e.toLowerCase();e="true"===r||"false"!==r&&e}return"boolean"!=typeof e&&(e=t.$_terms.truthy&&t.$_terms.truthy.has(e,null,null,!t._flags.sensitive)||(!t.$_terms.falsy||!t.$_terms.falsy.has(e,null,null,!t._flags.sensitive))&&e),{value:e}}},validate(e,{error:t}){if("boolean"!=typeof e)return{value:e,errors:t("boolean.base")}},rules:{truthy:{method(...e){a.verifyFlat(e,"truthy");const t=this.clone();t.$_terms.truthy=t.$_terms.truthy||new o;for(let r=0;r<e.length;++r){const n=e[r];s(void 0!==n,"Cannot call truthy with undefined"),t.$_terms.truthy.add(n)}return t}},falsy:{method(...e){a.verifyFlat(e,"falsy");const t=this.clone();t.$_terms.falsy=t.$_terms.falsy||new o;for(let r=0;r<e.length;++r){const n=e[r];s(void 0!==n,"Cannot call falsy with undefined"),t.$_terms.falsy.add(n)}return t}},sensitive:{method(e=!0){return this.$_setFlag("sensitive",e)}}},cast:{number:{from:i.isBool,to:(e,t)=>e?1:0},string:{from:i.isBool,to:(e,t)=>e?"true":"false"}},manifest:{build:(e,t)=>(t.truthy&&(e=e.truthy(...t.truthy)),t.falsy&&(e=e.falsy(...t.falsy)),e)},messages:{"boolean.base":"{{#label}} must be a boolean"}})},function(e,t,r){"use strict";const s=r(0),n=r(3),a=r(1),o=r(7),i={isDate:function(e){return e instanceof Date}};e.exports=n.extend({type:"date",coerce:{from:["number","string"],method:(e,{schema:t})=>({value:i.parse(e,t._flags.format)||e})},validate(e,{schema:t,error:r,prefs:s}){if(e instanceof Date&&!isNaN(e.getTime()))return;const n=t._flags.format;return s.convert&&n&&"string"==typeof e?{value:e,errors:r("date.format",{format:n})}:{value:e,errors:r("date.base")}},rules:{compare:{method:!1,validate(e,t,{date:r},{name:s,operator:n,args:o}){const i="now"===r?Date.now():r.getTime();return a.compare(e.getTime(),i,n)?e:t.error("date."+s,{limit:o.date,value:e})},args:[{name:"date",ref:!0,normalize:e=>"now"===e?e:i.parse(e),assert:e=>null!==e,message:"must have a valid date format"}]},format:{method(e){return s(["iso","javascript","unix"].includes(e),"Unknown date format",e),this.$_setFlag("format",e)}},greater:{method(e){return this.$_addRule({name:"greater",method:"compare",args:{date:e},operator:">"})}},iso:{method(){return this.format("iso")}},less:{method(e){return this.$_addRule({name:"less",method:"compare",args:{date:e},operator:"<"})}},max:{method(e){return this.$_addRule({name:"max",method:"compare",args:{date:e},operator:"<="})}},min:{method(e){return this.$_addRule({name:"min",method:"compare",args:{date:e},operator:">="})}},timestamp:{method(e="javascript"){return s(["javascript","unix"].includes(e),'"type" must be one of "javascript, unix"'),this.format(e)}}},cast:{number:{from:i.isDate,to:(e,t)=>e.getTime()},string:{from:i.isDate,to:(e,{prefs:t})=>o.date(e,t)}},messages:{"date.base":"{{#label}} must be a valid date","date.format":'{{#label}} must be in {msg("date.format." + #format) || #format} format',"date.greater":"{{#label}} must be greater than {{:#limit}}","date.less":"{{#label}} must be less than {{:#limit}}","date.max":"{{#label}} must be less than or equal to {{:#limit}}","date.min":"{{#label}} must be greater than or equal to {{:#limit}}","date.format.iso":"ISO 8601 date","date.format.javascript":"timestamp or number of milliseconds","date.format.unix":"timestamp or number of seconds"}}),i.parse=function(e,t){if(e instanceof Date)return e;if("string"!=typeof e&&(isNaN(e)||!isFinite(e)))return null;if(/^\s*$/.test(e))return null;if("iso"===t)return a.isIsoDate(e)?i.date(e.toString()):null;const r=e;if("string"==typeof e&&/^[+-]?\d+(\.\d+)?$/.test(e)&&(e=parseFloat(e)),t){if("javascript"===t)return i.date(1*e);if("unix"===t)return i.date(1e3*e);if("string"==typeof r)return null}return i.date(e)},i.date=function(e){const t=new Date(e);return isNaN(t.getTime())?null:t}},function(e,t,r){"use strict";const s=r(0),n=r(22);e.exports=n.extend({type:"function",properties:{typeof:"function"},rules:{arity:{method(e){return s(Number.isSafeInteger(e)&&e>=0,"n must be a positive integer"),this.$_addRule({name:"arity",args:{n:e}})},validate:(e,t,{n:r})=>e.length===r?e:t.error("function.arity",{n:r})},class:{method(){return this.$_addRule("class")},validate:(e,t)=>/^\s*class\s/.test(e.toString())?e:t.error("function.class",{value:e})},minArity:{method(e){return s(Number.isSafeInteger(e)&&e>0,"n must be a strict positive integer"),this.$_addRule({name:"minArity",args:{n:e}})},validate:(e,t,{n:r})=>e.length>=r?e:t.error("function.minArity",{n:r})},maxArity:{method(e){return s(Number.isSafeInteger(e)&&e>=0,"n must be a positive integer"),this.$_addRule({name:"maxArity",args:{n:e}})},validate:(e,t,{n:r})=>e.length<=r?e:t.error("function.maxArity",{n:r})}},messages:{"function.arity":"{{#label}} must have an arity of {{#n}}","function.class":"{{#label}} must be a class","function.maxArity":"{{#label}} must have an arity lesser or equal to {{#n}}","function.minArity":"{{#label}} must have an arity greater or equal to {{#n}}"}})},function(e,t,r){"use strict";const s=r(0),n=r(2),a=r(20),o=r(6),i={};e.exports=function(e,t,r={}){if(s(e&&"object"==typeof e,"Invalid defaults value: must be an object"),s(!t||!0===t||"object"==typeof t,"Invalid source value: must be true, falsy or an object"),s("object"==typeof r,"Invalid options: must be an object"),!t)return null;if(r.shallow)return i.applyToDefaultsWithShallow(e,t,r);const o=n(e);if(!0===t)return o;const l=void 0!==r.nullOverride&&r.nullOverride;return a(o,t,{nullOverride:l,mergeArrays:!1})},i.applyToDefaultsWithShallow=function(e,t,r){const l=r.shallow;s(Array.isArray(l),"Invalid keys");const c=new Map,u=!0===t?null:new Set;for(let r of l){r=Array.isArray(r)?r:r.split(".");const s=o(e,r);s&&"object"==typeof s?c.set(s,u&&o(t,r)||s):u&&u.add(r)}const f=n(e,{},c);if(!u)return f;for(const e of u)i.reachCopy(f,t,e);return a(f,t,{mergeArrays:!1,nullOverride:!1})},i.reachCopy=function(e,t,r){for(const e of r){if(!(e in t))return;t=t[e]}const s=t;let n=e;for(let e=0;e<r.length-1;++e){const t=r[e];"object"!=typeof n[t]&&(n[t]={}),n=n[t]}n[r[r.length-1]]=s}},function(e,t,r){"use strict";const s=r(0),n={};t.Sorter=class{constructor(){this._items=[],this.nodes=[]}add(e,t){const r=[].concat((t=t||{}).before||[]),n=[].concat(t.after||[]),a=t.group||"?",o=t.sort||0;s(!r.includes(a),"Item cannot come before itself: ".concat(a)),s(!r.includes("?"),"Item cannot come before unassociated items"),s(!n.includes(a),"Item cannot come after itself: ".concat(a)),s(!n.includes("?"),"Item cannot come after unassociated items"),Array.isArray(e)||(e=[e]);for(const t of e){const e={seq:this._items.length,sort:o,before:r,after:n,group:a,node:t};this._items.push(e)}const i=this._sort();return s(i,"item","?"!==a?"added into group ".concat(a):"","created a dependencies error"),this.nodes}merge(e){Array.isArray(e)||(e=[e]);for(const t of e)if(t)for(const e of t._items)this._items.push(Object.assign({},e));this._items.sort(n.mergeSort);for(let e=0;e<this._items.length;++e)this._items[e].seq=e;const t=this._sort();return s(t,"merge created a dependencies error"),this.nodes}_sort(){const e={},t=Object.create(null),r=Object.create(null);for(const s of this._items){const n=s.seq,a=s.group;r[a]=r[a]||[],r[a].push(n),e[n]=s.before;for(const e of s.after)t[e]=t[e]||[],t[e].push(n)}for(const t in e){const s=[];for(const n in e[t]){const a=e[t][n];r[a]=r[a]||[],s.push(...r[a])}e[t]=s}for(const s in t)if(r[s])for(const n of r[s])e[n].push(...t[s]);const s={};for(const t in e){const r=e[t];for(const e of r)s[e]=s[e]||[],s[e].push(t)}const n={},a=[];for(let e=0;e<this._items.length;++e){let t=e;if(s[e]){t=null;for(let e=0;e<this._items.length;++e){if(!0===n[e])continue;s[e]||(s[e]=[]);const r=s[e].length;let a=0;for(let t=0;t<r;++t)n[s[e][t]]&&++a;if(a===r){t=e;break}}}null!==t&&(n[t]=!0,a.push(t))}if(a.length!==this._items.length)return!1;const o={};for(const e of this._items)o[e.seq]=e;this._items=[],this.nodes=[];for(const e of a){const t=o[e];this.nodes.push(t.node),this._items.push(t)}return!0}},n.mergeSort=(e,t)=>e.sort===t.sort?0:e.sort<t.sort?-1:1},function(e,t,r){"use strict";const s=r(0),n=r(3),a=r(1),o=r(8),i=r(4),l={};e.exports=n.extend({type:"link",properties:{schemaChain:!0},terms:{link:{init:null,manifest:"single",register:!1}},args:(e,t)=>e.ref(t),validate(e,{schema:t,state:r,prefs:n}){s(t.$_terms.link,"Uninitialized link schema");const a=l.generate(t,e,r,n),o=t.$_terms.link[0].ref;return a.$_validate(e,r.nest(a,"link:".concat(o.display,":").concat(a.type)),n)},generate:(e,t,r,s)=>l.generate(e,t,r,s),rules:{ref:{method(e){s(!this.$_terms.link,"Cannot reinitialize schema"),e=o.ref(e),s("value"===e.type||"local"===e.type,"Invalid reference type:",e.type),s("local"===e.type||"root"===e.ancestor||e.ancestor>0,"Link cannot reference itself");const t=this.clone();return t.$_terms.link=[{ref:e}],t}},relative:{method(e=!0){return this.$_setFlag("relative",e)}}},overrides:{concat(e){s(this.$_terms.link,"Uninitialized link schema"),s(a.isSchema(e),"Invalid schema object"),s("link"!==e.type,"Cannot merge type link with another link");const t=this.clone();return t.$_terms.whens||(t.$_terms.whens=[]),t.$_terms.whens.push({concat:e}),t.$_mutateRebuild()}},manifest:{build:(e,t)=>(s(t.link,"Invalid link description missing link"),e.ref(t.link))}}),l.generate=function(e,t,r,s){let n=r.mainstay.links.get(e);if(n)return n._generate(t,r,s).schema;const a=e.$_terms.link[0].ref,{perspective:o,path:i}=l.perspective(a,r);l.assert(o,"which is outside of schema boundaries",a,e,r,s);try{n=i.length?o.$_reach(i):o}catch(t){l.assert(!1,"to non-existing schema",a,e,r,s)}return l.assert("link"!==n.type,"which is another link",a,e,r,s),e._flags.relative||r.mainstay.links.set(e,n),n._generate(t,r,s).schema},l.perspective=function(e,t){if("local"===e.type){for(const{schema:r,key:s}of t.schemas){if((r._flags.id||s)===e.path[0])return{perspective:r,path:e.path.slice(1)};if(r.$_terms.shared)for(const t of r.$_terms.shared)if(t._flags.id===e.path[0])return{perspective:t,path:e.path.slice(1)}}return{perspective:null,path:null}}return"root"===e.ancestor?{perspective:t.schemas[t.schemas.length-1].schema,path:e.path}:{perspective:t.schemas[e.ancestor]&&t.schemas[e.ancestor].schema,path:e.path}},l.assert=function(e,t,r,n,a,o){e||s(!1,'"'.concat(i.label(n._flags,a,o),'" contains link reference "').concat(r.display,'" ').concat(t))}},function(e,t,r){"use strict";const s=r(0),n=r(3),a=r(1),o={numberRx:/^\s*[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e([+-]?\d+))?\s*$/i,precisionRx:/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/};e.exports=n.extend({type:"number",flags:{unsafe:{default:!1}},coerce:{from:"string",method(e,{schema:t,error:r}){const s=e.match(o.numberRx);if(!s)return;e=e.trim();const n={value:parseFloat(e)};if(0===n.value&&(n.value=0),!t._flags.unsafe)if(e.match(/e/i)){if(o.normalizeExponent("".concat(n.value/Math.pow(10,s[1]),"e").concat(s[1]))!==o.normalizeExponent(e))return n.errors=r("number.unsafe"),n}else{const t=n.value.toString();if(t.match(/e/i))return n;if(t!==o.normalizeDecimal(e))return n.errors=r("number.unsafe"),n}return n}},validate(e,{schema:t,error:r,prefs:s}){if(e===1/0||e===-1/0)return{value:e,errors:r("number.infinity")};if(!a.isNumber(e))return{value:e,errors:r("number.base")};const n={value:e};if(s.convert){const e=t.$_getRule("precision");if(e){const t=Math.pow(10,e.args.limit);n.value=Math.round(n.value*t)/t}}return 0===n.value&&(n.value=0),!t._flags.unsafe&&(e>Number.MAX_SAFE_INTEGER||e<Number.MIN_SAFE_INTEGER)&&(n.errors=r("number.unsafe")),n},rules:{compare:{method:!1,validate:(e,t,{limit:r},{name:s,operator:n,args:o})=>a.compare(e,r,n)?e:t.error("number."+s,{limit:o.limit,value:e}),args:[{name:"limit",ref:!0,assert:a.isNumber,message:"must be a number"}]},greater:{method(e){return this.$_addRule({name:"greater",method:"compare",args:{limit:e},operator:">"})}},integer:{method(){return this.$_addRule("integer")},validate:(e,t)=>Math.trunc(e)-e==0?e:t.error("number.integer")},less:{method(e){return this.$_addRule({name:"less",method:"compare",args:{limit:e},operator:"<"})}},max:{method(e){return this.$_addRule({name:"max",method:"compare",args:{limit:e},operator:"<="})}},min:{method(e){return this.$_addRule({name:"min",method:"compare",args:{limit:e},operator:">="})}},multiple:{method(e){return this.$_addRule({name:"multiple",args:{base:e}})},validate:(e,t,{base:r},s)=>e%r==0?e:t.error("number.multiple",{multiple:s.args.base,value:e}),args:[{name:"base",ref:!0,assert:e=>"number"==typeof e&&isFinite(e)&&e>0,message:"must be a positive number"}],multi:!0},negative:{method(){return this.sign("negative")}},port:{method(){return this.$_addRule("port")},validate:(e,t)=>Number.isSafeInteger(e)&&e>=0&&e<=65535?e:t.error("number.port")},positive:{method(){return this.sign("positive")}},precision:{method(e){return s(Number.isSafeInteger(e),"limit must be an integer"),this.$_addRule({name:"precision",args:{limit:e}})},validate(e,t,{limit:r}){const s=e.toString().match(o.precisionRx);return Math.max((s[1]?s[1].length:0)-(s[2]?parseInt(s[2],10):0),0)<=r?e:t.error("number.precision",{limit:r,value:e})},convert:!0},sign:{method(e){return s(["negative","positive"].includes(e),"Invalid sign",e),this.$_addRule({name:"sign",args:{sign:e}})},validate:(e,t,{sign:r})=>"negative"===r&&e<0||"positive"===r&&e>0?e:t.error("number.".concat(r))},unsafe:{method(e=!0){return s("boolean"==typeof e,"enabled must be a boolean"),this.$_setFlag("unsafe",e)}}},cast:{string:{from:e=>"number"==typeof e,to:(e,t)=>e.toString()}},messages:{"number.base":"{{#label}} must be a number","number.greater":"{{#label}} must be greater than {{#limit}}","number.infinity":"{{#label}} cannot be infinity","number.integer":"{{#label}} must be an integer","number.less":"{{#label}} must be less than {{#limit}}","number.max":"{{#label}} must be less than or equal to {{#limit}}","number.min":"{{#label}} must be greater than or equal to {{#limit}}","number.multiple":"{{#label}} must be a multiple of {{#multiple}}","number.negative":"{{#label}} must be a negative number","number.port":"{{#label}} must be a valid port","number.positive":"{{#label}} must be a positive number","number.precision":"{{#label}} must have no more than {{#limit}} decimal places","number.unsafe":"{{#label}} must be a safe number"}}),o.normalizeExponent=function(e){return e.replace(/E/,"e").replace(/\.(\d*[1-9])?0+e/,".$1e").replace(/\.e/,"e").replace(/e\+/,"e").replace(/^\+/,"").replace(/^(-?)0+([1-9])/,"$1$2")},o.normalizeDecimal=function(e){return(e=e.replace(/^\+/,"").replace(/\.0*$/,"").replace(/^(-?)\.([^\.]*)$/,"$10.$2").replace(/^(-?)0+([0-9])/,"$1$2")).includes(".")&&e.endsWith("0")&&(e=e.replace(/0+$/,"")),"-0"===e?"0":e}},function(e,t,r){"use strict";const s=r(22);e.exports=s.extend({type:"object",cast:{map:{from:e=>e&&"object"==typeof e,to:(e,t)=>new Map(Object.entries(e))}}})},function(e,t,r){"use strict";function s(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,s)}return r}function n(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?s(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):s(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const o=r(0),i=r(23),l=r(49),c=r(50),u=r(27),f=r(51),m=r(26),h=r(3),p=r(1),d={tlds:f instanceof Set&&{tlds:{allow:f,deny:null}},base64Regex:{true:{true:/^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}==|[\w\-]{3}=)?$/,false:/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/},false:{true:/^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}(==)?|[\w\-]{3}=?)?$/,false:/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/}},dataUriRegex:/^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/,hexRegex:/^[a-f0-9]+$/i,ipRegex:c.regex().regex,isoDurationRegex:/^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/,guidBrackets:{"{":"}","[":"]","(":")","":""},guidVersions:{uuidv1:"1",uuidv2:"2",uuidv3:"3",uuidv4:"4",uuidv5:"5"},guidSeparators:new Set([void 0,!0,!1,"-",":"]),normalizationForms:["NFC","NFD","NFKC","NFKD"]};e.exports=h.extend({type:"string",flags:{insensitive:{default:!1},truncate:{default:!1}},terms:{replacements:{init:null}},coerce:{from:"string",method(e,{schema:t,state:r,prefs:s}){const n=t.$_getRule("normalize");n&&(e=e.normalize(n.args.form));const a=t.$_getRule("case");a&&(e="upper"===a.args.direction?e.toLocaleUpperCase():e.toLocaleLowerCase());const o=t.$_getRule("trim");if(o&&o.args.enabled&&(e=e.trim()),t.$_terms.replacements)for(const r of t.$_terms.replacements)e=e.replace(r.pattern,r.replacement);const i=t.$_getRule("hex");if(i&&i.args.options.byteAligned&&e.length%2!=0&&(e="0".concat(e)),t.$_getRule("isoDate")){const t=d.isoDate(e);t&&(e=t)}if(t._flags.truncate){const n=t.$_getRule("max");if(n){let a=n.args.limit;if(p.isResolvable(a)&&(a=a.resolve(e,r,s),!p.limit(a)))return{value:e,errors:t.$_createError("any.ref",a,{ref:n.args.limit,arg:"limit",reason:"must be a positive integer"},r,s)};e=e.slice(0,a)}}return{value:e}}},validate:(e,{error:t})=>"string"!=typeof e?{value:e,errors:t("string.base")}:""===e?{value:e,errors:t("string.empty")}:void 0,rules:{alphanum:{method(){return this.$_addRule("alphanum")},validate:(e,t)=>/^[a-zA-Z0-9]+$/.test(e)?e:t.error("string.alphanum")},base64:{method(e={}){return p.assertOptions(e,["paddingRequired","urlSafe"]),e=n({urlSafe:!1,paddingRequired:!0},e),o("boolean"==typeof e.paddingRequired,"paddingRequired must be boolean"),o("boolean"==typeof e.urlSafe,"urlSafe must be boolean"),this.$_addRule({name:"base64",args:{options:e}})},validate:(e,t,{options:r})=>d.base64Regex[r.paddingRequired][r.urlSafe].test(e)?e:t.error("string.base64")},case:{method(e){return o(["lower","upper"].includes(e),"Invalid case:",e),this.$_addRule({name:"case",args:{direction:e}})},validate:(e,t,{direction:r})=>"lower"===r&&e===e.toLocaleLowerCase()||"upper"===r&&e===e.toLocaleUpperCase()?e:t.error("string.".concat(r,"case")),convert:!0},creditCard:{method(){return this.$_addRule("creditCard")},validate(e,t){let r=e.length,s=0,n=1;for(;r--;){const t=e.charAt(r)*n;s+=t-9*(t>9),n^=3}return s>0&&s%10==0?e:t.error("string.creditCard")}},dataUri:{method(e={}){return p.assertOptions(e,["paddingRequired"]),e=n({paddingRequired:!0},e),o("boolean"==typeof e.paddingRequired,"paddingRequired must be boolean"),this.$_addRule({name:"dataUri",args:{options:e}})},validate(e,t,{options:r}){const s=e.match(d.dataUriRegex);if(s){if(!s[2])return e;if("base64"!==s[2])return e;if(d.base64Regex[r.paddingRequired].false.test(s[3]))return e}return t.error("string.dataUri")}},domain:{method(e){e&&p.assertOptions(e,["allowUnicode","maxDomainSegments","minDomainSegments","tlds"]);const t=d.addressOptions(e);return this.$_addRule({name:"domain",args:{options:e},address:t})},validate:(e,t,r,{address:s})=>i.isValid(e,s)?e:t.error("string.domain")},email:{method(e={}){p.assertOptions(e,["allowUnicode","ignoreLength","maxDomainSegments","minDomainSegments","multiple","separator","tlds"]),o(void 0===e.multiple||"boolean"==typeof e.multiple,"multiple option must be an boolean");const t=d.addressOptions(e),r=new RegExp("\\s*[".concat(e.separator?u(e.separator):",","]\\s*"));return this.$_addRule({name:"email",args:{options:e},regex:r,address:t})},validate(e,t,{options:r},{regex:s,address:n}){const a=r.multiple?e.split(s):[e],o=[];for(const e of a)l.isValid(e,n)||o.push(e);return o.length?t.error("string.email",{value:e,invalids:o}):e}},guid:{alias:"uuid",method(e={}){p.assertOptions(e,["version","separator"]);let t="";if(e.version){const r=[].concat(e.version);o(r.length>=1,"version must have at least 1 valid version specified");const s=new Set;for(let e=0;e<r.length;++e){const n=r[e];o("string"==typeof n,"version at position "+e+" must be a string");const a=d.guidVersions[n.toLowerCase()];o(a,"version at position "+e+" must be one of "+Object.keys(d.guidVersions).join(", ")),o(!s.has(a),"version at position "+e+" must not be a duplicate"),t+=a,s.add(a)}}o(d.guidSeparators.has(e.separator),'separator must be one of true, false, "-", or ":"');const r=void 0===e.separator?"[:-]?":!0===e.separator?"[:-]":!1===e.separator?"[]?":"\\".concat(e.separator),s=new RegExp("^([\\[{\\(]?)[0-9A-F]{8}(".concat(r,")[0-9A-F]{4}\\2?[").concat(t||"0-9A-F","][0-9A-F]{3}\\2?[").concat(t?"89AB":"0-9A-F","][0-9A-F]{3}\\2?[0-9A-F]{12}([\\]}\\)]?)$"),"i");return this.$_addRule({name:"guid",args:{options:e},regex:s})},validate(e,t,r,{regex:s}){const n=s.exec(e);return n?d.guidBrackets[n[1]]!==n[n.length-1]?t.error("string.guid"):e:t.error("string.guid")}},hex:{method(e={}){return p.assertOptions(e,["byteAligned"]),e=n({byteAligned:!1},e),o("boolean"==typeof e.byteAligned,"byteAligned must be boolean"),this.$_addRule({name:"hex",args:{options:e}})},validate:(e,t,{options:r})=>d.hexRegex.test(e)?r.byteAligned&&e.length%2!=0?t.error("string.hexAlign"):e:t.error("string.hex")},hostname:{method(){return this.$_addRule("hostname")},validate:(e,t)=>i.isValid(e,{minDomainSegments:1})||d.ipRegex.test(e)?e:t.error("string.hostname")},insensitive:{method(){return this.$_setFlag("insensitive",!0)}},ip:{method(e={}){p.assertOptions(e,["cidr","version"]);const{cidr:t,versions:r,regex:s}=c.regex(e),n=e.version?r:void 0;return this.$_addRule({name:"ip",args:{options:{cidr:t,version:n}},regex:s})},validate:(e,t,{options:r},{regex:s})=>s.test(e)?e:r.version?t.error("string.ipVersion",{value:e,cidr:r.cidr,version:r.version}):t.error("string.ip",{value:e,cidr:r.cidr})},isoDate:{method(){return this.$_addRule("isoDate")},validate:(e,{error:t})=>d.isoDate(e)?e:t("string.isoDate")},isoDuration:{method(){return this.$_addRule("isoDuration")},validate:(e,t)=>d.isoDurationRegex.test(e)?e:t.error("string.isoDuration")},length:{method(e,t){return d.length(this,"length",e,"=",t)},validate(e,t,{limit:r,encoding:s},{name:n,operator:a,args:o}){const i=!s&&e.length;return p.compare(i,r,a)?e:t.error("string."+n,{limit:o.limit,value:e,encoding:s})},args:[{name:"limit",ref:!0,assert:p.limit,message:"must be a positive integer"},"encoding"]},lowercase:{method(){return this.case("lower")}},max:{method(e,t){return d.length(this,"max",e,"<=",t)},args:["limit","encoding"]},min:{method(e,t){return d.length(this,"min",e,">=",t)},args:["limit","encoding"]},normalize:{method(e="NFC"){return o(d.normalizationForms.includes(e),"normalization form must be one of "+d.normalizationForms.join(", ")),this.$_addRule({name:"normalize",args:{form:e}})},validate:(e,{error:t},{form:r})=>e===e.normalize(r)?e:t("string.normalize",{value:e,form:r}),convert:!0},pattern:{alias:"regex",method(e,t={}){o(e instanceof RegExp,"regex must be a RegExp"),o(!e.flags.includes("g")&&!e.flags.includes("y"),"regex should not use global or sticky mode"),"string"==typeof t&&(t={name:t}),p.assertOptions(t,["invert","name"]);const r=["string.pattern",t.invert?".invert":"",t.name?".name":".base"].join("");return this.$_addRule({name:"pattern",args:{regex:e,options:t},errorCode:r})},validate:(e,t,{regex:r,options:s},{errorCode:n})=>r.test(e)^s.invert?e:t.error(n,{name:s.name,regex:r,value:e}),args:["regex","options"],multi:!0},replace:{method(e,t){"string"==typeof e&&(e=new RegExp(u(e),"g")),o(e instanceof RegExp,"pattern must be a RegExp"),o("string"==typeof t,"replacement must be a String");const r=this.clone();return r.$_terms.replacements||(r.$_terms.replacements=[]),r.$_terms.replacements.push({pattern:e,replacement:t}),r}},token:{method(){return this.$_addRule("token")},validate:(e,t)=>/^\w+$/.test(e)?e:t.error("string.token")},trim:{method(e=!0){return o("boolean"==typeof e,"enabled must be a boolean"),this.$_addRule({name:"trim",args:{enabled:e}})},validate:(e,t,{enabled:r})=>r&&e!==e.trim()?t.error("string.trim"):e,convert:!0},truncate:{method(e=!0){return o("boolean"==typeof e,"enabled must be a boolean"),this.$_setFlag("truncate",e)}},uppercase:{method(){return this.case("upper")}},uri:{method(e={}){p.assertOptions(e,["allowRelative","allowQuerySquareBrackets","domain","relativeOnly","scheme"]),e.domain&&p.assertOptions(e.domain,["allowUnicode","maxDomainSegments","minDomainSegments","tlds"]);const{regex:t,scheme:r}=m.regex(e),s=e.domain?d.addressOptions(e.domain):null;return this.$_addRule({name:"uri",args:{options:e},regex:t,domain:s,scheme:r})},validate(e,t,{options:r},{regex:s,domain:n,scheme:a}){if(["http:/","https:/"].includes(e))return t.error("string.uri");const o=s.exec(e);if(o){if(n){const e=o[1]||o[2];if(!i.isValid(e,n))return t.error("string.domain",{value:e})}return e}return r.relativeOnly?t.error("string.uriRelativeOnly"):r.scheme?t.error("string.uriCustomScheme",{scheme:a,value:e}):t.error("string.uri")}}},manifest:{build(e,t){if(t.replacements)for(const{pattern:r,replacement:s}of t.replacements)e=e.replace(r,s);return e}},messages:{"string.alphanum":"{{#label}} must only contain alpha-numeric characters","string.base":"{{#label}} must be a string","string.base64":"{{#label}} must be a valid base64 string","string.creditCard":"{{#label}} must be a credit card","string.dataUri":"{{#label}} must be a valid dataUri string","string.domain":"{{#label}} must contain a valid domain name","string.email":"{{#label}} must be a valid email","string.empty":"{{#label}} is not allowed to be empty","string.guid":"{{#label}} must be a valid GUID","string.hex":"{{#label}} must only contain hexadecimal characters","string.hexAlign":"{{#label}} hex decoded representation must be byte aligned","string.hostname":"{{#label}} must be a valid hostname","string.ip":"{{#label}} must be a valid ip address with a {{#cidr}} CIDR","string.ipVersion":"{{#label}} must be a valid ip address of one of the following versions {{#version}} with a {{#cidr}} CIDR","string.isoDate":"{{#label}} must be in iso format","string.isoDuration":"{{#label}} must be a valid ISO 8601 duration","string.length":"{{#label}} length must be {{#limit}} characters long","string.lowercase":"{{#label}} must only contain lowercase characters","string.max":"{{#label}} length must be less than or equal to {{#limit}} characters long","string.min":"{{#label}} length must be at least {{#limit}} characters long","string.normalize":"{{#label}} must be unicode normalized in the {{#form}} form","string.token":"{{#label}} must only contain alpha-numeric and underscore characters","string.pattern.base":"{{#label}} with value {:[.]} fails to match the required pattern: {{#regex}}","string.pattern.name":"{{#label}} with value {:[.]} fails to match the {{#name}} pattern","string.pattern.invert.base":"{{#label}} with value {:[.]} matches the inverted pattern: {{#regex}}","string.pattern.invert.name":"{{#label}} with value {:[.]} matches the inverted {{#name}} pattern","string.trim":"{{#label}} must not have leading or trailing whitespace","string.uri":"{{#label}} must be a valid uri","string.uriCustomScheme":"{{#label}} must be a valid uri with a scheme matching the {{#scheme}} pattern","string.uriRelativeOnly":"{{#label}} must be a valid relative uri","string.uppercase":"{{#label}} must only contain uppercase characters"}}),d.addressOptions=function(e){if(!e)return e;if(o(void 0===e.minDomainSegments||Number.isSafeInteger(e.minDomainSegments)&&e.minDomainSegments>0,"minDomainSegments must be a positive integer"),o(void 0===e.maxDomainSegments||Number.isSafeInteger(e.maxDomainSegments)&&e.maxDomainSegments>0,"maxDomainSegments must be a positive integer"),!1===e.tlds)return e;if(!0===e.tlds||void 0===e.tlds)return o(d.tlds,"Built-in TLD list disabled"),Object.assign({},e,d.tlds);o("object"==typeof e.tlds,"tlds must be true, false, or an object");const t=e.tlds.deny;if(t)return Array.isArray(t)&&(e=Object.assign({},e,{tlds:{deny:new Set(t)}})),o(e.tlds.deny instanceof Set,"tlds.deny must be an array, Set, or boolean"),o(!e.tlds.allow,"Cannot specify both tlds.allow and tlds.deny lists"),d.validateTlds(e.tlds.deny,"tlds.deny"),e;const r=e.tlds.allow;return r?!0===r?(o(d.tlds,"Built-in TLD list disabled"),Object.assign({},e,d.tlds)):(Array.isArray(r)&&(e=Object.assign({},e,{tlds:{allow:new Set(r)}})),o(e.tlds.allow instanceof Set,"tlds.allow must be an array, Set, or boolean"),d.validateTlds(e.tlds.allow,"tlds.allow"),e):e},d.validateTlds=function(e,t){for(const r of e)o(i.isValid(r,{minDomainSegments:1,maxDomainSegments:1}),"".concat(t," must contain valid top level domain names"))},d.isoDate=function(e){if(!p.isIsoDate(e))return null;/.*T.*[+-]\d\d$/.test(e)&&(e+="00");const t=new Date(e);return isNaN(t.getTime())?null:t.toISOString()},d.length=function(e,t,r,s,n){return o(!n||!1,"Invalid encoding:",n),e.$_addRule({name:t,method:"length",args:{limit:r,encoding:n},operator:s})}},function(e,t,r){"use strict";const s=r(24),n=r(23),a=r(25),o={nonAsciiRx:/[^\x00-\x7f]/,encoder:new(s.TextEncoder||TextEncoder)};t.analyze=function(e,t){return o.email(e,t)},t.isValid=function(e,t){return!o.email(e,t)},o.email=function(e,t={}){if("string"!=typeof e)throw new Error("Invalid input: email must be a string");if(!e)return a.code("EMPTY_STRING");const r=!o.nonAsciiRx.test(e);if(!r){if(!1===t.allowUnicode)return a.code("FORBIDDEN_UNICODE");e=e.normalize("NFC")}const s=e.split("@");if(2!==s.length)return s.length>2?a.code("MULTIPLE_AT_CHAR"):a.code("MISSING_AT_CHAR");const[i,l]=s;if(!i)return a.code("EMPTY_LOCAL");if(!t.ignoreLength){if(e.length>254)return a.code("ADDRESS_TOO_LONG");if(o.encoder.encode(i).length>64)return a.code("LOCAL_TOO_LONG")}return o.local(i,r)||n.analyze(l,t)},o.local=function(e,t){const r=e.split(".");for(const e of r){if(!e.length)return a.code("EMPTY_LOCAL_SEGMENT");if(t){if(!o.atextRx.test(e))return a.code("INVALID_LOCAL_CHARS")}else for(const t of e){if(o.atextRx.test(t))continue;const e=o.binary(t);if(!o.atomRx.test(e))return a.code("INVALID_LOCAL_CHARS")}}},o.binary=function(e){return Array.from(o.encoder.encode(e)).map(e=>String.fromCharCode(e)).join("")},o.atextRx=/^[\w!#\$%&'\*\+\-/=\?\^`\{\|\}~]+$/,o.atomRx=new RegExp(["(?:[\\xc2-\\xdf][\\x80-\\xbf])","(?:\\xe0[\\xa0-\\xbf][\\x80-\\xbf])|(?:[\\xe1-\\xec][\\x80-\\xbf]{2})|(?:\\xed[\\x80-\\x9f][\\x80-\\xbf])|(?:[\\xee-\\xef][\\x80-\\xbf]{2})","(?:\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2})|(?:[\\xf1-\\xf3][\\x80-\\xbf]{3})|(?:\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})"].join("|"))},function(e,t,r){"use strict";const s=r(0),n=r(26);t.regex=function(e={}){s(void 0===e.cidr||"string"==typeof e.cidr,"options.cidr must be a string");const t=e.cidr?e.cidr.toLowerCase():"optional";s(["required","optional","forbidden"].includes(t),"options.cidr must be one of required, optional, forbidden"),s(void 0===e.version||"string"==typeof e.version||Array.isArray(e.version),"options.version must be a string or an array of string");let r=e.version||["ipv4","ipv6","ipvfuture"];Array.isArray(r)||(r=[r]),s(r.length>=1,"options.version must have at least 1 version specified");for(let e=0;e<r.length;++e)s("string"==typeof r[e],"options.version must only contain strings"),r[e]=r[e].toLowerCase(),s(["ipv4","ipv6","ipvfuture"].includes(r[e]),"options.version contains unknown version "+r[e]+" - must be one of ipv4, ipv6, ipvfuture");r=Array.from(new Set(r));const a=r.map(e=>{if("forbidden"===t)return n.ip[e];const r="\\/".concat("ipv4"===e?n.ip.v4Cidr:n.ip.v6Cidr);return"required"===t?"".concat(n.ip[e]).concat(r):"".concat(n.ip[e],"(?:").concat(r,")?")}),o="(?:".concat(a.join("|"),")"),i=new RegExp("^".concat(o,"$"));return{cidr:t,versions:r,regex:i,raw:o}}},function(e,t){},function(e,t,r){"use strict";const s=r(0),n=r(3),a={};a.Map=class extends Map{slice(){return new a.Map(this)}},e.exports=n.extend({type:"symbol",terms:{map:{init:new a.Map}},coerce:{method(e,{schema:t,error:r}){const s=t.$_terms.map.get(e);return s&&(e=s),t._flags.only&&"symbol"!=typeof e?{value:e,errors:r("symbol.map",{map:t.$_terms.map})}:{value:e}}},validate(e,{error:t}){if("symbol"!=typeof e)return{value:e,errors:t("symbol.base")}},rules:{map:{method(e){e&&!e[Symbol.iterator]&&"object"==typeof e&&(e=Object.entries(e)),s(e&&e[Symbol.iterator],"Iterable must be an iterable or object");const t=this.clone(),r=[];for(const n of e){s(n&&n[Symbol.iterator],"Entry must be an iterable");const[e,a]=n;s("object"!=typeof e&&"function"!=typeof e&&"symbol"!=typeof e,"Key must not be of type object, function, or Symbol"),s("symbol"==typeof a,"Value must be a Symbol"),t.$_terms.map.set(e,a),r.push(a)}return t.valid(...r)}}},manifest:{build:(e,t)=>(t.map&&(e=e.map(t.map)),e)},messages:{"symbol.base":"{{#label}} must be a symbol","symbol.map":"{{#label}} must be one of {{#map}}"}})}])}));
\ No newline at end of file
diff --git a/node_modules/joi/lib/annotate.js b/node_modules/joi/lib/annotate.js
new file mode 100644
index 00000000..42798fc3
--- /dev/null
+++ b/node_modules/joi/lib/annotate.js
@@ -0,0 +1,175 @@
+'use strict';
+
+const Clone = require('@hapi/hoek/lib/clone');
+
+const Common = require('./common');
+
+
+const internals = {
+    annotations: Symbol('annotations')
+};
+
+
+exports.error = function (stripColorCodes) {
+
+    if (!this._original ||
+        typeof this._original !== 'object') {
+
+        return this.details[0].message;
+    }
+
+    const redFgEscape = stripColorCodes ? '' : '\u001b[31m';
+    const redBgEscape = stripColorCodes ? '' : '\u001b[41m';
+    const endColor = stripColorCodes ? '' : '\u001b[0m';
+
+    const obj = Clone(this._original);
+
+    for (let i = this.details.length - 1; i >= 0; --i) {        // Reverse order to process deepest child first
+        const pos = i + 1;
+        const error = this.details[i];
+        const path = error.path;
+        let node = obj;
+        for (let j = 0; ; ++j) {
+            const seg = path[j];
+
+            if (Common.isSchema(node)) {
+                node = node.clone();                              // joi schemas are not cloned by hoek, we have to take this extra step
+            }
+
+            if (j + 1 < path.length &&
+                typeof node[seg] !== 'string') {
+
+                node = node[seg];
+            }
+            else {
+                const refAnnotations = node[internals.annotations] || { errors: {}, missing: {} };
+                node[internals.annotations] = refAnnotations;
+
+                const cacheKey = seg || error.context.key;
+
+                if (node[seg] !== undefined) {
+                    refAnnotations.errors[cacheKey] = refAnnotations.errors[cacheKey] || [];
+                    refAnnotations.errors[cacheKey].push(pos);
+                }
+                else {
+                    refAnnotations.missing[cacheKey] = pos;
+                }
+
+                break;
+            }
+        }
+    }
+
+    const replacers = {
+        key: /_\$key\$_([, \d]+)_\$end\$_"/g,
+        missing: /"_\$miss\$_([^|]+)\|(\d+)_\$end\$_": "__missing__"/g,
+        arrayIndex: /\s*"_\$idx\$_([, \d]+)_\$end\$_",?\n(.*)/g,
+        specials: /"\[(NaN|Symbol.*|-?Infinity|function.*|\(.*)]"/g
+    };
+
+    let message = internals.safeStringify(obj, 2)
+        .replace(replacers.key, ($0, $1) => `" ${redFgEscape}[${$1}]${endColor}`)
+        .replace(replacers.missing, ($0, $1, $2) => `${redBgEscape}"${$1}"${endColor}${redFgEscape} [${$2}]: -- missing --${endColor}`)
+        .replace(replacers.arrayIndex, ($0, $1, $2) => `\n${$2} ${redFgEscape}[${$1}]${endColor}`)
+        .replace(replacers.specials, ($0, $1) => $1);
+
+    message = `${message}\n${redFgEscape}`;
+
+    for (let i = 0; i < this.details.length; ++i) {
+        const pos = i + 1;
+        message = `${message}\n[${pos}] ${this.details[i].message}`;
+    }
+
+    message = message + endColor;
+
+    return message;
+};
+
+
+// Inspired by json-stringify-safe
+
+internals.safeStringify = function (obj, spaces) {
+
+    return JSON.stringify(obj, internals.serializer(), spaces);
+};
+
+
+internals.serializer = function () {
+
+    const keys = [];
+    const stack = [];
+
+    const cycleReplacer = (key, value) => {
+
+        if (stack[0] === value) {
+            return '[Circular ~]';
+        }
+
+        return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
+    };
+
+    return function (key, value) {
+
+        if (stack.length > 0) {
+            const thisPos = stack.indexOf(this);
+            if (~thisPos) {
+                stack.length = thisPos + 1;
+                keys.length = thisPos + 1;
+                keys[thisPos] = key;
+            }
+            else {
+                stack.push(this);
+                keys.push(key);
+            }
+
+            if (~stack.indexOf(value)) {
+                value = cycleReplacer.call(this, key, value);
+            }
+        }
+        else {
+            stack.push(value);
+        }
+
+        if (value) {
+            const annotations = value[internals.annotations];
+            if (annotations) {
+                if (Array.isArray(value)) {
+                    const annotated = [];
+
+                    for (let i = 0; i < value.length; ++i) {
+                        if (annotations.errors[i]) {
+                            annotated.push(`_$idx$_${annotations.errors[i].sort().join(', ')}_$end$_`);
+                        }
+
+                        annotated.push(value[i]);
+                    }
+
+                    value = annotated;
+                }
+                else {
+                    for (const errorKey in annotations.errors) {
+                        value[`${errorKey}_$key$_${annotations.errors[errorKey].sort().join(', ')}_$end$_`] = value[errorKey];
+                        value[errorKey] = undefined;
+                    }
+
+                    for (const missingKey in annotations.missing) {
+                        value[`_$miss$_${missingKey}|${annotations.missing[missingKey]}_$end$_`] = '__missing__';
+                    }
+                }
+
+                return value;
+            }
+        }
+
+        if (value === Infinity ||
+            value === -Infinity ||
+            Number.isNaN(value) ||
+            typeof value === 'function' ||
+            typeof value === 'symbol') {
+
+            return '[' + value.toString() + ']';
+        }
+
+        return value;
+    };
+};
diff --git a/node_modules/joi/lib/base.js b/node_modules/joi/lib/base.js
new file mode 100644
index 00000000..309ae41e
--- /dev/null
+++ b/node_modules/joi/lib/base.js
@@ -0,0 +1,1068 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+const DeepEqual = require('@hapi/hoek/lib/deepEqual');
+const Merge = require('@hapi/hoek/lib/merge');
+
+const Cache = require('./cache');
+const Common = require('./common');
+const Compile = require('./compile');
+const Errors = require('./errors');
+const Extend = require('./extend');
+const Manifest = require('./manifest');
+const Messages = require('./messages');
+const Modify = require('./modify');
+const Ref = require('./ref');
+const Trace = require('./trace');
+const Validator = require('./validator');
+const Values = require('./values');
+
+
+const internals = {};
+
+
+internals.Base = class {
+
+    constructor(type) {
+
+        // Naming: public, _private, $_extension, $_mutate{action}
+
+        this.type = type;
+
+        this.$_root = null;
+        this._definition = {};
+        this._reset();
+    }
+
+    _reset() {
+
+        this._ids = new Modify.Ids();
+        this._preferences = null;
+        this._refs = new Ref.Manager();
+        this._cache = null;
+
+        this._valids = null;
+        this._invalids = null;
+
+        this._flags = {};
+        this._rules = [];
+        this._singleRules = new Map();              // The rule options passed for non-multi rules
+
+        this.$_terms = {};                          // Hash of arrays of immutable objects (extended by other types)
+
+        this.$_temp = {                             // Runtime state (not cloned)
+            ruleset: null,                          // null: use last, false: error, number: start position
+            whens: {}                               // Runtime cache of generated whens
+        };
+    }
+
+    // Manifest
+
+    describe() {
+
+        Assert(typeof Manifest.describe === 'function', 'Manifest functionality disabled');
+        return Manifest.describe(this);
+    }
+
+    // Rules
+
+    allow(...values) {
+
+        Common.verifyFlat(values, 'allow');
+        return this._values(values, '_valids');
+    }
+
+    alter(targets) {
+
+        Assert(targets && typeof targets === 'object' && !Array.isArray(targets), 'Invalid targets argument');
+        Assert(!this._inRuleset(), 'Cannot set alterations inside a ruleset');
+
+        const obj = this.clone();
+        obj.$_terms.alterations = obj.$_terms.alterations || [];
+        for (const target in targets) {
+            const adjuster = targets[target];
+            Assert(typeof adjuster === 'function', 'Alteration adjuster for', target, 'must be a function');
+            obj.$_terms.alterations.push({ target, adjuster });
+        }
+
+        obj.$_temp.ruleset = false;
+        return obj;
+    }
+
+    artifact(id) {
+
+        Assert(id !== undefined, 'Artifact cannot be undefined');
+        Assert(!this._cache, 'Cannot set an artifact with a rule cache');
+
+        return this.$_setFlag('artifact', id);
+    }
+
+    cast(to) {
+
+        Assert(to === false || typeof to === 'string', 'Invalid to value');
+        Assert(to === false || this._definition.cast[to], 'Type', this.type, 'does not support casting to', to);
+
+        return this.$_setFlag('cast', to === false ? undefined : to);
+    }
+
+    default(value, options) {
+
+        return this._default('default', value, options);
+    }
+
+    description(desc) {
+
+        Assert(desc && typeof desc === 'string', 'Description must be a non-empty string');
+
+        return this.$_setFlag('description', desc);
+    }
+
+    empty(schema) {
+
+        const obj = this.clone();
+
+        if (schema !== undefined) {
+            schema = obj.$_compile(schema, { override: false });
+        }
+
+        return obj.$_setFlag('empty', schema, { clone: false });
+    }
+
+    error(err) {
+
+        Assert(err, 'Missing error');
+        Assert(err instanceof Error || typeof err === 'function', 'Must provide a valid Error object or a function');
+
+        return this.$_setFlag('error', err);
+    }
+
+    example(example, options = {}) {
+
+        Assert(example !== undefined, 'Missing example');
+        Common.assertOptions(options, ['override']);
+
+        return this._inner('examples', example, { single: true, override: options.override });
+    }
+
+    external(method, description) {
+
+        if (typeof method === 'object') {
+            Assert(!description, 'Cannot combine options with description');
+            description = method.description;
+            method = method.method;
+        }
+
+        Assert(typeof method === 'function', 'Method must be a function');
+        Assert(description === undefined || description && typeof description === 'string', 'Description must be a non-empty string');
+
+        return this._inner('externals', { method, description }, { single: true });
+    }
+
+    failover(value, options) {
+
+        return this._default('failover', value, options);
+    }
+
+    forbidden() {
+
+        return this.presence('forbidden');
+    }
+
+    id(id) {
+
+        if (!id) {
+            return this.$_setFlag('id', undefined);
+        }
+
+        Assert(typeof id === 'string', 'id must be a non-empty string');
+        Assert(/^[^\.]+$/.test(id), 'id cannot contain period character');
+
+        return this.$_setFlag('id', id);
+    }
+
+    invalid(...values) {
+
+        return this._values(values, '_invalids');
+    }
+
+    label(name) {
+
+        Assert(name && typeof name === 'string', 'Label name must be a non-empty string');
+
+        return this.$_setFlag('label', name);
+    }
+
+    meta(meta) {
+
+        Assert(meta !== undefined, 'Meta cannot be undefined');
+
+        return this._inner('metas', meta, { single: true });
+    }
+
+    note(...notes) {
+
+        Assert(notes.length, 'Missing notes');
+        for (const note of notes) {
+            Assert(note && typeof note === 'string', 'Notes must be non-empty strings');
+        }
+
+        return this._inner('notes', notes);
+    }
+
+    only(mode = true) {
+
+        Assert(typeof mode === 'boolean', 'Invalid mode:', mode);
+
+        return this.$_setFlag('only', mode);
+    }
+
+    optional() {
+
+        return this.presence('optional');
+    }
+
+    prefs(prefs) {
+
+        Assert(prefs, 'Missing preferences');
+        Assert(prefs.context === undefined, 'Cannot override context');
+        Assert(prefs.externals === undefined, 'Cannot override externals');
+        Assert(prefs.warnings === undefined, 'Cannot override warnings');
+        Assert(prefs.debug === undefined, 'Cannot override debug');
+
+        Common.checkPreferences(prefs);
+
+        const obj = this.clone();
+        obj._preferences = Common.preferences(obj._preferences, prefs);
+        return obj;
+    }
+
+    presence(mode) {
+
+        Assert(['optional', 'required', 'forbidden'].includes(mode), 'Unknown presence mode', mode);
+
+        return this.$_setFlag('presence', mode);
+    }
+
+    raw(enabled = true) {
+
+        return this.$_setFlag('result', enabled ? 'raw' : undefined);
+    }
+
+    result(mode) {
+
+        Assert(['raw', 'strip'].includes(mode), 'Unknown result mode', mode);
+
+        return this.$_setFlag('result', mode);
+    }
+
+    required() {
+
+        return this.presence('required');
+    }
+
+    strict(enabled) {
+
+        const obj = this.clone();
+
+        const convert = enabled === undefined ? false : !enabled;
+        obj._preferences = Common.preferences(obj._preferences, { convert });
+        return obj;
+    }
+
+    strip(enabled = true) {
+
+        return this.$_setFlag('result', enabled ? 'strip' : undefined);
+    }
+
+    tag(...tags) {
+
+        Assert(tags.length, 'Missing tags');
+        for (const tag of tags) {
+            Assert(tag && typeof tag === 'string', 'Tags must be non-empty strings');
+        }
+
+        return this._inner('tags', tags);
+    }
+
+    unit(name) {
+
+        Assert(name && typeof name === 'string', 'Unit name must be a non-empty string');
+
+        return this.$_setFlag('unit', name);
+    }
+
+    valid(...values) {
+
+        Common.verifyFlat(values, 'valid');
+
+        const obj = this.allow(...values);
+        obj.$_setFlag('only', !!obj._valids, { clone: false });
+        return obj;
+    }
+
+    when(condition, options) {
+
+        const obj = this.clone();
+
+        if (!obj.$_terms.whens) {
+            obj.$_terms.whens = [];
+        }
+
+        const when = Compile.when(obj, condition, options);
+        if (!['any', 'link'].includes(obj.type)) {
+            const conditions = when.is ? [when] : when.switch;
+            for (const item of conditions) {
+                Assert(!item.then || item.then.type === 'any' || item.then.type === obj.type, 'Cannot combine', obj.type, 'with', item.then && item.then.type);
+                Assert(!item.otherwise || item.otherwise.type === 'any' || item.otherwise.type === obj.type, 'Cannot combine', obj.type, 'with', item.otherwise && item.otherwise.type);
+
+            }
+        }
+
+        obj.$_terms.whens.push(when);
+        return obj.$_mutateRebuild();
+    }
+
+    // Helpers
+
+    cache(cache) {
+
+        Assert(!this._inRuleset(), 'Cannot set caching inside a ruleset');
+        Assert(!this._cache, 'Cannot override schema cache');
+        Assert(this._flags.artifact === undefined, 'Cannot cache a rule with an artifact');
+
+        const obj = this.clone();
+        obj._cache = cache || Cache.provider.provision();
+        obj.$_temp.ruleset = false;
+        return obj;
+    }
+
+    clone() {
+
+        const obj = Object.create(Object.getPrototypeOf(this));
+        return this._assign(obj);
+    }
+
+    concat(source) {
+
+        Assert(Common.isSchema(source), 'Invalid schema object');
+        Assert(this.type === 'any' || source.type === 'any' || source.type === this.type, 'Cannot merge type', this.type, 'with another type:', source.type);
+        Assert(!this._inRuleset(), 'Cannot concatenate onto a schema with open ruleset');
+        Assert(!source._inRuleset(), 'Cannot concatenate a schema with open ruleset');
+
+        let obj = this.clone();
+
+        if (this.type === 'any' &&
+            source.type !== 'any') {
+
+            // Change obj to match source type
+
+            const tmpObj = source.clone();
+            for (const key of Object.keys(obj)) {
+                if (key !== 'type') {
+                    tmpObj[key] = obj[key];
+                }
+            }
+
+            obj = tmpObj;
+        }
+
+        obj._ids.concat(source._ids);
+        obj._refs.register(source, Ref.toSibling);
+
+        obj._preferences = obj._preferences ? Common.preferences(obj._preferences, source._preferences) : source._preferences;
+        obj._valids = Values.merge(obj._valids, source._valids, source._invalids);
+        obj._invalids = Values.merge(obj._invalids, source._invalids, source._valids);
+
+        // Remove unique rules present in source
+
+        for (const name of source._singleRules.keys()) {
+            if (obj._singleRules.has(name)) {
+                obj._rules = obj._rules.filter((target) => target.keep || target.name !== name);
+                obj._singleRules.delete(name);
+            }
+        }
+
+        // Rules
+
+        for (const test of source._rules) {
+            if (!source._definition.rules[test.method].multi) {
+                obj._singleRules.set(test.name, test);
+            }
+
+            obj._rules.push(test);
+        }
+
+        // Flags
+
+        if (obj._flags.empty &&
+            source._flags.empty) {
+
+            obj._flags.empty = obj._flags.empty.concat(source._flags.empty);
+            const flags = Object.assign({}, source._flags);
+            delete flags.empty;
+            Merge(obj._flags, flags);
+        }
+        else if (source._flags.empty) {
+            obj._flags.empty = source._flags.empty;
+            const flags = Object.assign({}, source._flags);
+            delete flags.empty;
+            Merge(obj._flags, flags);
+        }
+        else {
+            Merge(obj._flags, source._flags);
+        }
+
+        // Terms
+
+        for (const key in source.$_terms) {
+            const terms = source.$_terms[key];
+            if (!terms) {
+                if (!obj.$_terms[key]) {
+                    obj.$_terms[key] = terms;
+                }
+
+                continue;
+            }
+
+            if (!obj.$_terms[key]) {
+                obj.$_terms[key] = terms.slice();
+                continue;
+            }
+
+            obj.$_terms[key] = obj.$_terms[key].concat(terms);
+        }
+
+        // Tracing
+
+        if (this.$_root._tracer) {
+            this.$_root._tracer._combine(obj, [this, source]);
+        }
+
+        // Rebuild
+
+        return obj.$_mutateRebuild();
+    }
+
+    extend(options) {
+
+        Assert(!options.base, 'Cannot extend type with another base');
+
+        return Extend.type(this, options);
+    }
+
+    extract(path) {
+
+        path = Array.isArray(path) ? path : path.split('.');
+        return this._ids.reach(path);
+    }
+
+    fork(paths, adjuster) {
+
+        Assert(!this._inRuleset(), 'Cannot fork inside a ruleset');
+
+        let obj = this;                                             // eslint-disable-line consistent-this
+        for (let path of [].concat(paths)) {
+            path = Array.isArray(path) ? path : path.split('.');
+            obj = obj._ids.fork(path, adjuster, obj);
+        }
+
+        obj.$_temp.ruleset = false;
+        return obj;
+    }
+
+    rule(options) {
+
+        const def = this._definition;
+        Common.assertOptions(options, Object.keys(def.modifiers));
+
+        Assert(this.$_temp.ruleset !== false, 'Cannot apply rules to empty ruleset or the last rule added does not support rule properties');
+        const start = this.$_temp.ruleset === null ? this._rules.length - 1 : this.$_temp.ruleset;
+        Assert(start >= 0 && start < this._rules.length, 'Cannot apply rules to empty ruleset');
+
+        const obj = this.clone();
+
+        for (let i = start; i < obj._rules.length; ++i) {
+            const original = obj._rules[i];
+            const rule = Clone(original);
+
+            for (const name in options) {
+                def.modifiers[name](rule, options[name]);
+                Assert(rule.name === original.name, 'Cannot change rule name');
+            }
+
+            obj._rules[i] = rule;
+
+            if (obj._singleRules.get(rule.name) === original) {
+                obj._singleRules.set(rule.name, rule);
+            }
+        }
+
+        obj.$_temp.ruleset = false;
+        return obj.$_mutateRebuild();
+    }
+
+    get ruleset() {
+
+        Assert(!this._inRuleset(), 'Cannot start a new ruleset without closing the previous one');
+
+        const obj = this.clone();
+        obj.$_temp.ruleset = obj._rules.length;
+        return obj;
+    }
+
+    get $() {
+
+        return this.ruleset;
+    }
+
+    tailor(targets) {
+
+        targets = [].concat(targets);
+
+        Assert(!this._inRuleset(), 'Cannot tailor inside a ruleset');
+
+        let obj = this;                                                     // eslint-disable-line consistent-this
+
+        if (this.$_terms.alterations) {
+            for (const { target, adjuster } of this.$_terms.alterations) {
+                if (targets.includes(target)) {
+                    obj = adjuster(obj);
+                    Assert(Common.isSchema(obj), 'Alteration adjuster for', target, 'failed to return a schema object');
+                }
+            }
+        }
+
+        obj = obj.$_modify({ each: (item) => item.tailor(targets), ref: false });
+        obj.$_temp.ruleset = false;
+        return obj.$_mutateRebuild();
+    }
+
+    tracer() {
+
+        return Trace.location ? Trace.location(this) : this;                // $lab:coverage:ignore$
+    }
+
+    validate(value, options) {
+
+        return Validator.entry(value, this, options);
+    }
+
+    validateAsync(value, options) {
+
+        return Validator.entryAsync(value, this, options);
+    }
+
+    // Extensions
+
+    $_addRule(options) {
+
+        // Normalize rule
+
+        if (typeof options === 'string') {
+            options = { name: options };
+        }
+
+        Assert(options && typeof options === 'object', 'Invalid options');
+        Assert(options.name && typeof options.name === 'string', 'Invalid rule name');
+
+        for (const key in options) {
+            Assert(key[0] !== '_', 'Cannot set private rule properties');
+        }
+
+        const rule = Object.assign({}, options);        // Shallow cloned
+        rule._resolve = [];
+        rule.method = rule.method || rule.name;
+
+        const definition = this._definition.rules[rule.method];
+        const args = rule.args;
+
+        Assert(definition, 'Unknown rule', rule.method);
+
+        // Args
+
+        const obj = this.clone();
+
+        if (args) {
+            Assert(Object.keys(args).length === 1 || Object.keys(args).length === this._definition.rules[rule.name].args.length, 'Invalid rule definition for', this.type, rule.name);
+
+            for (const key in args) {
+                let arg = args[key];
+                if (arg === undefined) {
+                    delete args[key];
+                    continue;
+                }
+
+                if (definition.argsByName) {
+                    const resolver = definition.argsByName.get(key);
+
+                    if (resolver.ref &&
+                        Common.isResolvable(arg)) {
+
+                        rule._resolve.push(key);
+                        obj.$_mutateRegister(arg);
+                    }
+                    else {
+                        if (resolver.normalize) {
+                            arg = resolver.normalize(arg);
+                            args[key] = arg;
+                        }
+
+                        if (resolver.assert) {
+                            const error = Common.validateArg(arg, key, resolver);
+                            Assert(!error, error, 'or reference');
+                        }
+                    }
+                }
+
+                args[key] = arg;
+            }
+        }
+
+        // Unique rules
+
+        if (!definition.multi) {
+            obj._ruleRemove(rule.name, { clone: false });
+            obj._singleRules.set(rule.name, rule);
+        }
+
+        if (obj.$_temp.ruleset === false) {
+            obj.$_temp.ruleset = null;
+        }
+
+        if (definition.priority) {
+            obj._rules.unshift(rule);
+        }
+        else {
+            obj._rules.push(rule);
+        }
+
+        return obj;
+    }
+
+    $_compile(schema, options) {
+
+        return Compile.schema(this.$_root, schema, options);
+    }
+
+    $_createError(code, value, local, state, prefs, options = {}) {
+
+        const flags = options.flags !== false ? this._flags : {};
+        const messages = options.messages ? Messages.merge(this._definition.messages, options.messages) : this._definition.messages;
+        return new Errors.Report(code, value, local, flags, messages, state, prefs);
+    }
+
+    $_getFlag(name) {
+
+        return this._flags[name];
+    }
+
+    $_getRule(name) {
+
+        return this._singleRules.get(name);
+    }
+
+    $_mapLabels(path) {
+
+        path = Array.isArray(path) ? path : path.split('.');
+        return this._ids.labels(path);
+    }
+
+    $_match(value, state, prefs, overrides) {
+
+        prefs = Object.assign({}, prefs);       // Shallow cloned
+        prefs.abortEarly = true;
+        prefs._externals = false;
+
+        state.snapshot();
+        const result = !Validator.validate(value, this, state, prefs, overrides).errors;
+        state.restore();
+
+        return result;
+    }
+
+    $_modify(options) {
+
+        Common.assertOptions(options, ['each', 'once', 'ref', 'schema']);
+        return Modify.schema(this, options) || this;
+    }
+
+    $_mutateRebuild() {
+
+        Assert(!this._inRuleset(), 'Cannot add this rule inside a ruleset');
+
+        this._refs.reset();
+        this._ids.reset();
+
+        const each = (item, { source, name, path, key }) => {
+
+            const family = this._definition[source][name] && this._definition[source][name].register;
+            if (family !== false) {
+                this.$_mutateRegister(item, { family, key });
+            }
+        };
+
+        this.$_modify({ each });
+
+        if (this._definition.rebuild) {
+            this._definition.rebuild(this);
+        }
+
+        this.$_temp.ruleset = false;
+        return this;
+    }
+
+    $_mutateRegister(schema, { family, key } = {}) {
+
+        this._refs.register(schema, family);
+        this._ids.register(schema, { key });
+    }
+
+    $_property(name) {
+
+        return this._definition.properties[name];
+    }
+
+    $_reach(path) {
+
+        return this._ids.reach(path);
+    }
+
+    $_rootReferences() {
+
+        return this._refs.roots();
+    }
+
+    $_setFlag(name, value, options = {}) {
+
+        Assert(name[0] === '_' || !this._inRuleset(), 'Cannot set flag inside a ruleset');
+
+        const flag = this._definition.flags[name] || {};
+        if (DeepEqual(value, flag.default)) {
+            value = undefined;
+        }
+
+        if (DeepEqual(value, this._flags[name])) {
+            return this;
+        }
+
+        const obj = options.clone !== false ? this.clone() : this;
+
+        if (value !== undefined) {
+            obj._flags[name] = value;
+            obj.$_mutateRegister(value);
+        }
+        else {
+            delete obj._flags[name];
+        }
+
+        if (name[0] !== '_') {
+            obj.$_temp.ruleset = false;
+        }
+
+        return obj;
+    }
+
+    $_parent(method, ...args) {
+
+        return this[method][Common.symbols.parent].call(this, ...args);
+    }
+
+    $_validate(value, state, prefs) {
+
+        return Validator.validate(value, this, state, prefs);
+    }
+
+    // Internals
+
+    _assign(target) {
+
+        target.type = this.type;
+
+        target.$_root = this.$_root;
+
+        target.$_temp = Object.assign({}, this.$_temp);
+        target.$_temp.whens = {};
+
+        target._ids = this._ids.clone();
+        target._preferences = this._preferences;
+        target._valids = this._valids && this._valids.clone();
+        target._invalids = this._invalids && this._invalids.clone();
+        target._rules = this._rules.slice();
+        target._singleRules = Clone(this._singleRules, { shallow: true });
+        target._refs = this._refs.clone();
+        target._flags = Object.assign({}, this._flags);
+        target._cache = null;
+
+        target.$_terms = {};
+        for (const key in this.$_terms) {
+            target.$_terms[key] = this.$_terms[key] ? this.$_terms[key].slice() : null;
+        }
+
+        // Backwards compatibility
+
+        target.$_super = {};
+        for (const override in this.$_super) {
+            target.$_super[override] = this._super[override].bind(target);
+        }
+
+        return target;
+    }
+
+    _bare() {
+
+        const obj = this.clone();
+        obj._reset();
+
+        const terms = obj._definition.terms;
+        for (const name in terms) {
+            const term = terms[name];
+            obj.$_terms[name] = term.init;
+        }
+
+        return obj.$_mutateRebuild();
+    }
+
+    _default(flag, value, options = {}) {
+
+        Common.assertOptions(options, 'literal');
+
+        Assert(value !== undefined, 'Missing', flag, 'value');
+        Assert(typeof value === 'function' || !options.literal, 'Only function value supports literal option');
+
+        if (typeof value === 'function' &&
+            options.literal) {
+
+            value = {
+                [Common.symbols.literal]: true,
+                literal: value
+            };
+        }
+
+        const obj = this.$_setFlag(flag, value);
+        return obj;
+    }
+
+    _generate(value, state, prefs) {
+
+        if (!this.$_terms.whens) {
+            return { schema: this };
+        }
+
+        // Collect matching whens
+
+        const whens = [];
+        const ids = [];
+        for (let i = 0; i < this.$_terms.whens.length; ++i) {
+            const when = this.$_terms.whens[i];
+
+            if (when.concat) {
+                whens.push(when.concat);
+                ids.push(`${i}.concat`);
+                continue;
+            }
+
+            const input = when.ref ? when.ref.resolve(value, state, prefs) : value;
+            const tests = when.is ? [when] : when.switch;
+            const before = ids.length;
+
+            for (let j = 0; j < tests.length; ++j) {
+                const { is, then, otherwise } = tests[j];
+
+                const baseId = `${i}${when.switch ? '.' + j : ''}`;
+                if (is.$_match(input, state.nest(is, `${baseId}.is`), prefs)) {
+                    if (then) {
+                        const localState = state.localize([...state.path, `${baseId}.then`], state.ancestors, state.schemas);
+                        const { schema: generated, id } = then._generate(value, localState, prefs);
+                        whens.push(generated);
+                        ids.push(`${baseId}.then${id ? `(${id})` : ''}`);
+                        break;
+                    }
+                }
+                else if (otherwise) {
+                    const localState = state.localize([...state.path, `${baseId}.otherwise`], state.ancestors, state.schemas);
+                    const { schema: generated, id } = otherwise._generate(value, localState, prefs);
+                    whens.push(generated);
+                    ids.push(`${baseId}.otherwise${id ? `(${id})` : ''}`);
+                    break;
+                }
+            }
+
+            if (when.break &&
+                ids.length > before) {          // Something matched
+
+                break;
+            }
+        }
+
+        // Check cache
+
+        const id = ids.join(', ');
+        state.mainstay.tracer.debug(state, 'rule', 'when', id);
+
+        if (!id) {
+            return { schema: this };
+        }
+
+        if (!state.mainstay.tracer.active &&
+            this.$_temp.whens[id]) {
+
+            return { schema: this.$_temp.whens[id], id };
+        }
+
+        // Generate dynamic schema
+
+        let obj = this;                                             // eslint-disable-line consistent-this
+        if (this._definition.generate) {
+            obj = this._definition.generate(this, value, state, prefs);
+        }
+
+        // Apply whens
+
+        for (const when of whens) {
+            obj = obj.concat(when);
+        }
+
+        // Tracing
+
+        if (this.$_root._tracer) {
+            this.$_root._tracer._combine(obj, [this, ...whens]);
+        }
+
+        // Cache result
+
+        this.$_temp.whens[id] = obj;
+        return { schema: obj, id };
+    }
+
+    _inner(type, values, options = {}) {
+
+        Assert(!this._inRuleset(), `Cannot set ${type} inside a ruleset`);
+
+        const obj = this.clone();
+        if (!obj.$_terms[type] ||
+            options.override) {
+
+            obj.$_terms[type] = [];
+        }
+
+        if (options.single) {
+            obj.$_terms[type].push(values);
+        }
+        else {
+            obj.$_terms[type].push(...values);
+        }
+
+        obj.$_temp.ruleset = false;
+        return obj;
+    }
+
+    _inRuleset() {
+
+        return this.$_temp.ruleset !== null && this.$_temp.ruleset !== false;
+    }
+
+    _ruleRemove(name, options = {}) {
+
+        if (!this._singleRules.has(name)) {
+            return this;
+        }
+
+        const obj = options.clone !== false ? this.clone() : this;
+
+        obj._singleRules.delete(name);
+
+        const filtered = [];
+        for (let i = 0; i < obj._rules.length; ++i) {
+            const test = obj._rules[i];
+            if (test.name === name &&
+                !test.keep) {
+
+                if (obj._inRuleset() &&
+                    i < obj.$_temp.ruleset) {
+
+                    --obj.$_temp.ruleset;
+                }
+
+                continue;
+            }
+
+            filtered.push(test);
+        }
+
+        obj._rules = filtered;
+        return obj;
+    }
+
+    _values(values, key) {
+
+        Common.verifyFlat(values, key.slice(1, -1));
+
+        const obj = this.clone();
+
+        const override = values[0] === Common.symbols.override;
+        if (override) {
+            values = values.slice(1);
+        }
+
+        if (!obj[key] &&
+            values.length) {
+
+            obj[key] = new Values();
+        }
+        else if (override) {
+            obj[key] = values.length ? new Values() : null;
+            obj.$_mutateRebuild();
+        }
+
+        if (!obj[key]) {
+            return obj;
+        }
+
+        if (override) {
+            obj[key].override();
+        }
+
+        for (const value of values) {
+            Assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
+            Assert(value !== Common.symbols.override, 'Override must be the first value');
+
+            const other = key === '_invalids' ? '_valids' : '_invalids';
+            if (obj[other]) {
+                obj[other].remove(value);
+                if (!obj[other].length) {
+                    Assert(key === '_valids' || !obj._flags.only, 'Setting invalid value', value, 'leaves schema rejecting all values due to previous valid rule');
+                    obj[other] = null;
+                }
+            }
+
+            obj[key].add(value, obj._refs);
+        }
+
+        return obj;
+    }
+};
+
+
+internals.Base.prototype[Common.symbols.any] = {
+    version: Common.version,
+    compile: Compile.compile,
+    root: '$_root'
+};
+
+
+internals.Base.prototype.isImmutable = true;                // Prevents Hoek from deep cloning schema objects (must be on prototype)
+
+
+// Aliases
+
+internals.Base.prototype.deny = internals.Base.prototype.invalid;
+internals.Base.prototype.disallow = internals.Base.prototype.invalid;
+internals.Base.prototype.equal = internals.Base.prototype.valid;
+internals.Base.prototype.exist = internals.Base.prototype.required;
+internals.Base.prototype.not = internals.Base.prototype.invalid;
+internals.Base.prototype.options = internals.Base.prototype.prefs;
+internals.Base.prototype.preferences = internals.Base.prototype.prefs;
+
+
+module.exports = new internals.Base();
diff --git a/node_modules/joi/lib/cache.js b/node_modules/joi/lib/cache.js
new file mode 100644
index 00000000..32c61e0e
--- /dev/null
+++ b/node_modules/joi/lib/cache.js
@@ -0,0 +1,143 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+
+const Common = require('./common');
+
+
+const internals = {
+    max: 1000,
+    supported: new Set(['undefined', 'boolean', 'number', 'string'])
+};
+
+
+exports.provider = {
+
+    provision(options) {
+
+        return new internals.Cache(options);
+    }
+};
+
+
+// Least Recently Used (LRU) Cache
+
+internals.Cache = class {
+
+    constructor(options = {}) {
+
+        Common.assertOptions(options, ['max']);
+        Assert(options.max === undefined || options.max && options.max > 0 && isFinite(options.max), 'Invalid max cache size');
+
+        this._max = options.max || internals.max;
+
+        this._map = new Map();                          // Map of nodes by key
+        this._list = new internals.List();              // List of nodes (most recently used in head)
+    }
+
+    get length() {
+
+        return this._map.size;
+    }
+
+    set(key, value) {
+
+        if (key !== null &&
+            !internals.supported.has(typeof key)) {
+
+            return;
+        }
+
+        let node = this._map.get(key);
+        if (node) {
+            node.value = value;
+            this._list.first(node);
+            return;
+        }
+
+        node = this._list.unshift({ key, value });
+        this._map.set(key, node);
+        this._compact();
+    }
+
+    get(key) {
+
+        const node = this._map.get(key);
+        if (node) {
+            this._list.first(node);
+            return Clone(node.value);
+        }
+    }
+
+    _compact() {
+
+        if (this._map.size > this._max) {
+            const node = this._list.pop();
+            this._map.delete(node.key);
+        }
+    }
+};
+
+
+internals.List = class {
+
+    constructor() {
+
+        this.tail = null;
+        this.head = null;
+    }
+
+    unshift(node) {
+
+        node.next = null;
+        node.prev = this.head;
+
+        if (this.head) {
+            this.head.next = node;
+        }
+
+        this.head = node;
+
+        if (!this.tail) {
+            this.tail = node;
+        }
+
+        return node;
+    }
+
+    first(node) {
+
+        if (node === this.head) {
+            return;
+        }
+
+        this._remove(node);
+        this.unshift(node);
+    }
+
+    pop() {
+
+        return this._remove(this.tail);
+    }
+
+    _remove(node) {
+
+        const { next, prev } = node;
+
+        next.prev = prev;
+
+        if (prev) {
+            prev.next = next;
+        }
+
+        if (node === this.tail) {
+            this.tail = next;
+        }
+
+        node.prev = null;
+        node.next = null;
+
+        return node;
+    }
+};
diff --git a/node_modules/joi/lib/common.js b/node_modules/joi/lib/common.js
new file mode 100644
index 00000000..7d572c13
--- /dev/null
+++ b/node_modules/joi/lib/common.js
@@ -0,0 +1,216 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const AssertError = require('@hapi/hoek/lib/error');
+
+const Pkg = require('../package.json');
+
+let Messages;
+let Schemas;
+
+
+const internals = {
+    isoDate: /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/
+};
+
+
+exports.version = Pkg.version;
+
+
+exports.defaults = {
+    abortEarly: true,
+    allowUnknown: false,
+    artifacts: false,
+    cache: true,
+    context: null,
+    convert: true,
+    dateFormat: 'iso',
+    errors: {
+        escapeHtml: false,
+        label: 'path',
+        language: null,
+        render: true,
+        stack: false,
+        wrap: {
+            label: '"',
+            array: '[]'
+        }
+    },
+    externals: true,
+    messages: {},
+    nonEnumerables: false,
+    noDefaults: false,
+    presence: 'optional',
+    skipFunctions: false,
+    stripUnknown: false,
+    warnings: false
+};
+
+
+exports.symbols = {
+    any: Symbol.for('@hapi/joi/schema'),            // Used to internally identify any-based types (shared with other joi versions)
+    arraySingle: Symbol('arraySingle'),
+    deepDefault: Symbol('deepDefault'),
+    errors: Symbol('errors'),
+    literal: Symbol('literal'),
+    override: Symbol('override'),
+    parent: Symbol('parent'),
+    prefs: Symbol('prefs'),
+    ref: Symbol('ref'),
+    template: Symbol('template'),
+    values: Symbol('values')
+};
+
+
+exports.assertOptions = function (options, keys, name = 'Options') {
+
+    Assert(options && typeof options === 'object' && !Array.isArray(options), 'Options must be of type object');
+    const unknownKeys = Object.keys(options).filter((k) => !keys.includes(k));
+    Assert(unknownKeys.length === 0, `${name} contain unknown keys: ${unknownKeys}`);
+};
+
+
+exports.checkPreferences = function (prefs) {
+
+    Schemas = Schemas || require('./schemas');
+
+    const result = Schemas.preferences.validate(prefs);
+
+    if (result.error) {
+        throw new AssertError([result.error.details[0].message]);
+    }
+};
+
+
+exports.compare = function (a, b, operator) {
+
+    switch (operator) {
+        case '=': return a === b;
+        case '>': return a > b;
+        case '<': return a < b;
+        case '>=': return a >= b;
+        case '<=': return a <= b;
+    }
+};
+
+
+exports.default = function (value, defaultValue) {
+
+    return value === undefined ? defaultValue : value;
+};
+
+
+exports.isIsoDate = function (date) {
+
+    return internals.isoDate.test(date);
+};
+
+
+exports.isNumber = function (value) {
+
+    return typeof value === 'number' && !isNaN(value);
+};
+
+
+exports.isResolvable = function (obj) {
+
+    if (!obj) {
+        return false;
+    }
+
+    return obj[exports.symbols.ref] || obj[exports.symbols.template];
+};
+
+
+exports.isSchema = function (schema, options = {}) {
+
+    const any = schema && schema[exports.symbols.any];
+    if (!any) {
+        return false;
+    }
+
+    Assert(options.legacy || any.version === exports.version, 'Cannot mix different versions of joi schemas');
+    return true;
+};
+
+
+exports.isValues = function (obj) {
+
+    return obj[exports.symbols.values];
+};
+
+
+exports.limit = function (value) {
+
+    return Number.isSafeInteger(value) && value >= 0;
+};
+
+
+exports.preferences = function (target, source) {
+
+    Messages = Messages || require('./messages');
+
+    target = target || {};
+    source = source || {};
+
+    const merged = Object.assign({}, target, source);
+    if (source.errors &&
+        target.errors) {
+
+        merged.errors = Object.assign({}, target.errors, source.errors);
+        merged.errors.wrap = Object.assign({}, target.errors.wrap, source.errors.wrap);
+    }
+
+    if (source.messages) {
+        merged.messages = Messages.compile(source.messages, target.messages);
+    }
+
+    delete merged[exports.symbols.prefs];
+    return merged;
+};
+
+
+exports.tryWithPath = function (fn, key, options = {}) {
+
+    try {
+        return fn();
+    }
+    catch (err) {
+        if (err.path !== undefined) {
+            err.path = key + '.' + err.path;
+        }
+        else {
+            err.path = key;
+        }
+
+        if (options.append) {
+            err.message = `${err.message} (${err.path})`;
+        }
+
+        throw err;
+    }
+};
+
+
+exports.validateArg = function (value, label, { assert, message }) {
+
+    if (exports.isSchema(assert)) {
+        const result = assert.validate(value);
+        if (!result.error) {
+            return;
+        }
+
+        return result.error.message;
+    }
+    else if (!assert(value)) {
+        return label ? `${label} ${message}` : message;
+    }
+};
+
+
+exports.verifyFlat = function (args, method) {
+
+    for (const arg of args) {
+        Assert(!Array.isArray(arg), 'Method no longer accepts array arguments:', method);
+    }
+};
diff --git a/node_modules/joi/lib/compile.js b/node_modules/joi/lib/compile.js
new file mode 100644
index 00000000..5593b7c9
--- /dev/null
+++ b/node_modules/joi/lib/compile.js
@@ -0,0 +1,283 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Common = require('./common');
+const Ref = require('./ref');
+
+
+const internals = {};
+
+
+exports.schema = function (Joi, config, options = {}) {
+
+    Common.assertOptions(options, ['appendPath', 'override']);
+
+    try {
+        return internals.schema(Joi, config, options);
+    }
+    catch (err) {
+        if (options.appendPath &&
+            err.path !== undefined) {
+
+            err.message = `${err.message} (${err.path})`;
+        }
+
+        throw err;
+    }
+};
+
+
+internals.schema = function (Joi, config, options) {
+
+    Assert(config !== undefined, 'Invalid undefined schema');
+
+    if (Array.isArray(config)) {
+        Assert(config.length, 'Invalid empty array schema');
+
+        if (config.length === 1) {
+            config = config[0];
+        }
+    }
+
+    const valid = (base, ...values) => {
+
+        if (options.override !== false) {
+            return base.valid(Joi.override, ...values);
+        }
+
+        return base.valid(...values);
+    };
+
+    if (internals.simple(config)) {
+        return valid(Joi, config);
+    }
+
+    if (typeof config === 'function') {
+        return Joi.custom(config);
+    }
+
+    Assert(typeof config === 'object', 'Invalid schema content:', typeof config);
+
+    if (Common.isResolvable(config)) {
+        return valid(Joi, config);
+    }
+
+    if (Common.isSchema(config)) {
+        return config;
+    }
+
+    if (Array.isArray(config)) {
+        for (const item of config) {
+            if (!internals.simple(item)) {
+                return Joi.alternatives().try(...config);
+            }
+        }
+
+        return valid(Joi, ...config);
+    }
+
+    if (config instanceof RegExp) {
+        return Joi.string().regex(config);
+    }
+
+    if (config instanceof Date) {
+        return valid(Joi.date(), config);
+    }
+
+    Assert(Object.getPrototypeOf(config) === Object.getPrototypeOf({}), 'Schema can only contain plain objects');
+
+    return Joi.object().keys(config);
+};
+
+
+exports.ref = function (id, options) {
+
+    return Ref.isRef(id) ? id : Ref.create(id, options);
+};
+
+
+exports.compile = function (root, schema, options = {}) {
+
+    Common.assertOptions(options, ['legacy']);
+
+    // Compiled by any supported version
+
+    const any = schema && schema[Common.symbols.any];
+    if (any) {
+        Assert(options.legacy || any.version === Common.version, 'Cannot mix different versions of joi schemas:', any.version, Common.version);
+        return schema;
+    }
+
+    // Uncompiled root
+
+    if (typeof schema !== 'object' ||
+        !options.legacy) {
+
+        return exports.schema(root, schema, { appendPath: true });          // Will error if schema contains other versions
+    }
+
+    // Scan schema for compiled parts
+
+    const compiler = internals.walk(schema);
+    if (!compiler) {
+        return exports.schema(root, schema, { appendPath: true });
+    }
+
+    return compiler.compile(compiler.root, schema);
+};
+
+
+internals.walk = function (schema) {
+
+    if (typeof schema !== 'object') {
+        return null;
+    }
+
+    if (Array.isArray(schema)) {
+        for (const item of schema) {
+            const compiler = internals.walk(item);
+            if (compiler) {
+                return compiler;
+            }
+        }
+
+        return null;
+    }
+
+    const any = schema[Common.symbols.any];
+    if (any) {
+        return { root: schema[any.root], compile: any.compile };
+    }
+
+    Assert(Object.getPrototypeOf(schema) === Object.getPrototypeOf({}), 'Schema can only contain plain objects');
+
+    for (const key in schema) {
+        const compiler = internals.walk(schema[key]);
+        if (compiler) {
+            return compiler;
+        }
+    }
+
+    return null;
+};
+
+
+internals.simple = function (value) {
+
+    return value === null || ['boolean', 'string', 'number'].includes(typeof value);
+};
+
+
+exports.when = function (schema, condition, options) {
+
+    if (options === undefined) {
+        Assert(condition && typeof condition === 'object', 'Missing options');
+
+        options = condition;
+        condition = Ref.create('.');
+    }
+
+    if (Array.isArray(options)) {
+        options = { switch: options };
+    }
+
+    Common.assertOptions(options, ['is', 'not', 'then', 'otherwise', 'switch', 'break']);
+
+    // Schema condition
+
+    if (Common.isSchema(condition)) {
+        Assert(options.is === undefined, '"is" can not be used with a schema condition');
+        Assert(options.not === undefined, '"not" can not be used with a schema condition');
+        Assert(options.switch === undefined, '"switch" can not be used with a schema condition');
+
+        return internals.condition(schema, { is: condition, then: options.then, otherwise: options.otherwise, break: options.break });
+    }
+
+    // Single condition
+
+    Assert(Ref.isRef(condition) || typeof condition === 'string', 'Invalid condition:', condition);
+    Assert(options.not === undefined || options.is === undefined, 'Cannot combine "is" with "not"');
+
+    if (options.switch === undefined) {
+        let rule = options;
+        if (options.not !== undefined) {
+            rule = { is: options.not, then: options.otherwise, otherwise: options.then, break: options.break };
+        }
+
+        let is = rule.is !== undefined ? schema.$_compile(rule.is) : schema.$_root.invalid(null, false, 0, '').required();
+        Assert(rule.then !== undefined || rule.otherwise !== undefined, 'options must have at least one of "then", "otherwise", or "switch"');
+        Assert(rule.break === undefined || rule.then === undefined || rule.otherwise === undefined, 'Cannot specify then, otherwise, and break all together');
+
+        if (options.is !== undefined &&
+            !Ref.isRef(options.is) &&
+            !Common.isSchema(options.is)) {
+
+            is = is.required();                     // Only apply required if this wasn't already a schema or a ref
+        }
+
+        return internals.condition(schema, { ref: exports.ref(condition), is, then: rule.then, otherwise: rule.otherwise, break: rule.break });
+    }
+
+    // Switch statement
+
+    Assert(Array.isArray(options.switch), '"switch" must be an array');
+    Assert(options.is === undefined, 'Cannot combine "switch" with "is"');
+    Assert(options.not === undefined, 'Cannot combine "switch" with "not"');
+    Assert(options.then === undefined, 'Cannot combine "switch" with "then"');
+
+    const rule = {
+        ref: exports.ref(condition),
+        switch: [],
+        break: options.break
+    };
+
+    for (let i = 0; i < options.switch.length; ++i) {
+        const test = options.switch[i];
+        const last = i === options.switch.length - 1;
+
+        Common.assertOptions(test, last ? ['is', 'then', 'otherwise'] : ['is', 'then']);
+
+        Assert(test.is !== undefined, 'Switch statement missing "is"');
+        Assert(test.then !== undefined, 'Switch statement missing "then"');
+
+        const item = {
+            is: schema.$_compile(test.is),
+            then: schema.$_compile(test.then)
+        };
+
+        if (!Ref.isRef(test.is) &&
+            !Common.isSchema(test.is)) {
+
+            item.is = item.is.required();           // Only apply required if this wasn't already a schema or a ref
+        }
+
+        if (last) {
+            Assert(options.otherwise === undefined || test.otherwise === undefined, 'Cannot specify "otherwise" inside and outside a "switch"');
+            const otherwise = options.otherwise !== undefined ? options.otherwise : test.otherwise;
+            if (otherwise !== undefined) {
+                Assert(rule.break === undefined, 'Cannot specify both otherwise and break');
+                item.otherwise = schema.$_compile(otherwise);
+            }
+        }
+
+        rule.switch.push(item);
+    }
+
+    return rule;
+};
+
+
+internals.condition = function (schema, condition) {
+
+    for (const key of ['then', 'otherwise']) {
+        if (condition[key] === undefined) {
+            delete condition[key];
+        }
+        else {
+            condition[key] = schema.$_compile(condition[key]);
+        }
+    }
+
+    return condition;
+};
diff --git a/node_modules/joi/lib/errors.js b/node_modules/joi/lib/errors.js
new file mode 100644
index 00000000..0823f924
--- /dev/null
+++ b/node_modules/joi/lib/errors.js
@@ -0,0 +1,262 @@
+'use strict';
+
+const Annotate = require('./annotate');
+const Common = require('./common');
+const Template = require('./template');
+
+
+const internals = {};
+
+
+exports.Report = class {
+
+    constructor(code, value, local, flags, messages, state, prefs) {
+
+        this.code = code;
+        this.flags = flags;
+        this.messages = messages;
+        this.path = state.path;
+        this.prefs = prefs;
+        this.state = state;
+        this.value = value;
+
+        this.message = null;
+        this.template = null;
+
+        this.local = local || {};
+        this.local.label = exports.label(this.flags, this.state, this.prefs, this.messages);
+
+        if (this.value !== undefined &&
+            !this.local.hasOwnProperty('value')) {
+
+            this.local.value = this.value;
+        }
+
+        if (this.path.length) {
+            const key = this.path[this.path.length - 1];
+            if (typeof key !== 'object') {
+                this.local.key = key;
+            }
+        }
+    }
+
+    _setTemplate(template) {
+
+        this.template = template;
+
+        if (!this.flags.label &&
+            this.path.length === 0) {
+
+            const localized = this._template(this.template, 'root');
+            if (localized) {
+                this.local.label = localized;
+            }
+        }
+    }
+
+    toString() {
+
+        if (this.message) {
+            return this.message;
+        }
+
+        const code = this.code;
+
+        if (!this.prefs.errors.render) {
+            return this.code;
+        }
+
+        const template = this._template(this.template) ||
+            this._template(this.prefs.messages) ||
+            this._template(this.messages);
+
+        if (template === undefined) {
+            return `Error code "${code}" is not defined, your custom type is missing the correct messages definition`;
+        }
+
+        // Render and cache result
+
+        this.message = template.render(this.value, this.state, this.prefs, this.local, { errors: this.prefs.errors, messages: [this.prefs.messages, this.messages] });
+        if (!this.prefs.errors.label) {
+            this.message = this.message.replace(/^"" /, '').trim();
+        }
+
+        return this.message;
+    }
+
+    _template(messages, code) {
+
+        return exports.template(this.value, messages, code || this.code, this.state, this.prefs);
+    }
+};
+
+
+exports.path = function (path) {
+
+    let label = '';
+    for (const segment of path) {
+        if (typeof segment === 'object') {          // Exclude array single path segment
+            continue;
+        }
+
+        if (typeof segment === 'string') {
+            if (label) {
+                label += '.';
+            }
+
+            label += segment;
+        }
+        else {
+            label += `[${segment}]`;
+        }
+    }
+
+    return label;
+};
+
+
+exports.template = function (value, messages, code, state, prefs) {
+
+    if (!messages) {
+        return;
+    }
+
+    if (Template.isTemplate(messages)) {
+        return code !== 'root' ? messages : null;
+    }
+
+    let lang = prefs.errors.language;
+    if (Common.isResolvable(lang)) {
+        lang = lang.resolve(value, state, prefs);
+    }
+
+    if (lang &&
+        messages[lang] &&
+        messages[lang][code] !== undefined) {
+
+        return messages[lang][code];
+    }
+
+    return messages[code];
+};
+
+
+exports.label = function (flags, state, prefs, messages) {
+
+    if (flags.label) {
+        return flags.label;
+    }
+
+    if (!prefs.errors.label) {
+        return '';
+    }
+
+    let path = state.path;
+    if (prefs.errors.label === 'key' &&
+        state.path.length > 1) {
+
+        path = state.path.slice(-1);
+    }
+
+    const normalized = exports.path(path);
+    if (normalized) {
+        return normalized;
+    }
+
+    return exports.template(null, prefs.messages, 'root', state, prefs) ||
+        messages && exports.template(null, messages, 'root', state, prefs) ||
+        'value';
+};
+
+
+exports.process = function (errors, original, prefs) {
+
+    if (!errors) {
+        return null;
+    }
+
+    const { override, message, details } = exports.details(errors);
+    if (override) {
+        return override;
+    }
+
+    if (prefs.errors.stack) {
+        return new exports.ValidationError(message, details, original);
+    }
+
+    const limit = Error.stackTraceLimit;
+    Error.stackTraceLimit = 0;
+    const validationError = new exports.ValidationError(message, details, original);
+    Error.stackTraceLimit = limit;
+    return validationError;
+};
+
+
+exports.details = function (errors, options = {}) {
+
+    let messages = [];
+    const details = [];
+
+    for (const item of errors) {
+
+        // Override
+
+        if (item instanceof Error) {
+            if (options.override !== false) {
+                return { override: item };
+            }
+
+            const message = item.toString();
+            messages.push(message);
+
+            details.push({
+                message,
+                type: 'override',
+                context: { error: item }
+            });
+
+            continue;
+        }
+
+        // Report
+
+        const message = item.toString();
+        messages.push(message);
+
+        details.push({
+            message,
+            path: item.path.filter((v) => typeof v !== 'object'),
+            type: item.code,
+            context: item.local
+        });
+    }
+
+    if (messages.length > 1) {
+        messages = [...new Set(messages)];
+    }
+
+    return { message: messages.join('. '), details };
+};
+
+
+exports.ValidationError = class extends Error {
+
+    constructor(message, details, original) {
+
+        super(message);
+        this._original = original;
+        this.details = details;
+    }
+
+    static isError(err) {
+
+        return err instanceof exports.ValidationError;
+    }
+};
+
+
+exports.ValidationError.prototype.isJoi = true;
+
+exports.ValidationError.prototype.name = 'ValidationError';
+
+exports.ValidationError.prototype.annotate = Annotate.error;
diff --git a/node_modules/joi/lib/extend.js b/node_modules/joi/lib/extend.js
new file mode 100644
index 00000000..2a5acf7b
--- /dev/null
+++ b/node_modules/joi/lib/extend.js
@@ -0,0 +1,312 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+
+const Common = require('./common');
+const Messages = require('./messages');
+
+
+const internals = {};
+
+
+exports.type = function (from, options) {
+
+    const base = Object.getPrototypeOf(from);
+    const prototype = Clone(base);
+    const schema = from._assign(Object.create(prototype));
+    const def = Object.assign({}, options);                                 // Shallow cloned
+    delete def.base;
+
+    prototype._definition = def;
+
+    const parent = base._definition || {};
+    def.messages = Messages.merge(parent.messages, def.messages);
+    def.properties = Object.assign({}, parent.properties, def.properties);
+
+    // Type
+
+    schema.type = def.type;
+
+    // Flags
+
+    def.flags = Object.assign({}, parent.flags, def.flags);
+
+    // Terms
+
+    const terms = Object.assign({}, parent.terms);
+    if (def.terms) {
+        for (const name in def.terms) {                                     // Only apply own terms
+            const term = def.terms[name];
+            Assert(schema.$_terms[name] === undefined, 'Invalid term override for', def.type, name);
+            schema.$_terms[name] = term.init;
+            terms[name] = term;
+        }
+    }
+
+    def.terms = terms;
+
+    // Constructor arguments
+
+    if (!def.args) {
+        def.args = parent.args;
+    }
+
+    // Prepare
+
+    def.prepare = internals.prepare(def.prepare, parent.prepare);
+
+    // Coerce
+
+    if (def.coerce) {
+        if (typeof def.coerce === 'function') {
+            def.coerce = { method: def.coerce };
+        }
+
+        if (def.coerce.from &&
+            !Array.isArray(def.coerce.from)) {
+
+            def.coerce = { method: def.coerce.method, from: [].concat(def.coerce.from) };
+        }
+    }
+
+    def.coerce = internals.coerce(def.coerce, parent.coerce);
+
+    // Validate
+
+    def.validate = internals.validate(def.validate, parent.validate);
+
+    // Rules
+
+    const rules = Object.assign({}, parent.rules);
+    if (def.rules) {
+        for (const name in def.rules) {
+            const rule = def.rules[name];
+            Assert(typeof rule === 'object', 'Invalid rule definition for', def.type, name);
+
+            let method = rule.method;
+            if (method === undefined) {
+                method = function () {
+
+                    return this.$_addRule(name);
+                };
+            }
+
+            if (method) {
+                Assert(!prototype[name], 'Rule conflict in', def.type, name);
+                prototype[name] = method;
+            }
+
+            Assert(!rules[name], 'Rule conflict in', def.type, name);
+            rules[name] = rule;
+
+            if (rule.alias) {
+                const aliases = [].concat(rule.alias);
+                for (const alias of aliases) {
+                    prototype[alias] = rule.method;
+                }
+            }
+
+            if (rule.args) {
+                rule.argsByName = new Map();
+                rule.args = rule.args.map((arg) => {
+
+                    if (typeof arg === 'string') {
+                        arg = { name: arg };
+                    }
+
+                    Assert(!rule.argsByName.has(arg.name), 'Duplicated argument name', arg.name);
+
+                    if (Common.isSchema(arg.assert)) {
+                        arg.assert = arg.assert.strict().label(arg.name);
+                    }
+
+                    rule.argsByName.set(arg.name, arg);
+                    return arg;
+                });
+            }
+        }
+    }
+
+    def.rules = rules;
+
+    // Modifiers
+
+    const modifiers = Object.assign({}, parent.modifiers);
+    if (def.modifiers) {
+        for (const name in def.modifiers) {
+            Assert(!prototype[name], 'Rule conflict in', def.type, name);
+
+            const modifier = def.modifiers[name];
+            Assert(typeof modifier === 'function', 'Invalid modifier definition for', def.type, name);
+
+            const method = function (arg) {
+
+                return this.rule({ [name]: arg });
+            };
+
+            prototype[name] = method;
+            modifiers[name] = modifier;
+        }
+    }
+
+    def.modifiers = modifiers;
+
+    // Overrides
+
+    if (def.overrides) {
+        prototype._super = base;
+        schema.$_super = {};                                                            // Backwards compatibility
+        for (const override in def.overrides) {
+            Assert(base[override], 'Cannot override missing', override);
+            def.overrides[override][Common.symbols.parent] = base[override];
+            schema.$_super[override] = base[override].bind(schema);                     // Backwards compatibility
+        }
+
+        Object.assign(prototype, def.overrides);
+    }
+
+    // Casts
+
+    def.cast = Object.assign({}, parent.cast, def.cast);
+
+    // Manifest
+
+    const manifest = Object.assign({}, parent.manifest, def.manifest);
+    manifest.build = internals.build(def.manifest && def.manifest.build, parent.manifest && parent.manifest.build);
+    def.manifest = manifest;
+
+    // Rebuild
+
+    def.rebuild = internals.rebuild(def.rebuild, parent.rebuild);
+
+    return schema;
+};
+
+
+// Helpers
+
+internals.build = function (child, parent) {
+
+    if (!child ||
+        !parent) {
+
+        return child || parent;
+    }
+
+    return function (obj, desc) {
+
+        return parent(child(obj, desc), desc);
+    };
+};
+
+
+internals.coerce = function (child, parent) {
+
+    if (!child ||
+        !parent) {
+
+        return child || parent;
+    }
+
+    return {
+        from: child.from && parent.from ? [...new Set([...child.from, ...parent.from])] : null,
+        method(value, helpers) {
+
+            let coerced;
+            if (!parent.from ||
+                parent.from.includes(typeof value)) {
+
+                coerced = parent.method(value, helpers);
+                if (coerced) {
+                    if (coerced.errors ||
+                        coerced.value === undefined) {
+
+                        return coerced;
+                    }
+
+                    value = coerced.value;
+                }
+            }
+
+            if (!child.from ||
+                child.from.includes(typeof value)) {
+
+                const own = child.method(value, helpers);
+                if (own) {
+                    return own;
+                }
+            }
+
+            return coerced;
+        }
+    };
+};
+
+
+internals.prepare = function (child, parent) {
+
+    if (!child ||
+        !parent) {
+
+        return child || parent;
+    }
+
+    return function (value, helpers) {
+
+        const prepared = child(value, helpers);
+        if (prepared) {
+            if (prepared.errors ||
+                prepared.value === undefined) {
+
+                return prepared;
+            }
+
+            value = prepared.value;
+        }
+
+        return parent(value, helpers) || prepared;
+    };
+};
+
+
+internals.rebuild = function (child, parent) {
+
+    if (!child ||
+        !parent) {
+
+        return child || parent;
+    }
+
+    return function (schema) {
+
+        parent(schema);
+        child(schema);
+    };
+};
+
+
+internals.validate = function (child, parent) {
+
+    if (!child ||
+        !parent) {
+
+        return child || parent;
+    }
+
+    return function (value, helpers) {
+
+        const result = parent(value, helpers);
+        if (result) {
+            if (result.errors &&
+                (!Array.isArray(result.errors) || result.errors.length)) {
+
+                return result;
+            }
+
+            value = result.value;
+        }
+
+        return child(value, helpers) || result;
+    };
+};
diff --git a/node_modules/joi/lib/index.d.ts b/node_modules/joi/lib/index.d.ts
new file mode 100644
index 00000000..2b2f7453
--- /dev/null
+++ b/node_modules/joi/lib/index.d.ts
@@ -0,0 +1,2206 @@
+// The following definitions have been copied (almost) as-is from:
+// https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/hapi__joi
+// 
+// Note: This file is expected to change dramatically in the next major release and have been
+// imported here to make migrating back to the "joi" module name simpler. It include known bugs
+// and other issues. It does not include some new features included in version 17.2.0 or newer.
+//
+// TypeScript Version: 2.8
+
+// TODO express type of Schema in a type-parameter (.default, .valid, .example etc)
+
+declare namespace Joi {
+    type Types =
+        | 'any'
+        | 'alternatives'
+        | 'array'
+        | 'boolean'
+        | 'binary'
+        | 'date'
+        | 'function'
+        | 'link'
+        | 'number'
+        | 'object'
+        | 'string'
+        | 'symbol';
+
+    type BasicType = boolean | number | string | any[] | object | null;
+
+    type LanguageMessages = Record<string, string>;
+
+    type PresenceMode = 'optional' | 'required' | 'forbidden';
+
+    interface ErrorFormattingOptions {
+        /**
+         * when true, error message templates will escape special characters to HTML entities, for security purposes.
+         *
+         * @default false
+         */
+        escapeHtml?: boolean;
+        /**
+         * defines the value used to set the label context variable.
+         */
+        label?: 'path' | 'key' | false;
+        /**
+         * The preferred language code for error messages.
+         * The value is matched against keys at the root of the messages object, and then the error code as a child key of that.
+         * Can be a reference to the value, global context, or local context which is the root value passed to the validation function.
+         *
+         * Note that references to the value are usually not what you want as they move around the value structure relative to where the error happens.
+         * Instead, either use the global context, or the absolute value (e.g. `Joi.ref('/variable')`)
+         */
+        language?: keyof LanguageMessages;
+        /**
+         * when false, skips rendering error templates. Useful when error messages are generated elsewhere to save processing time.
+         *
+         * @default true
+         */
+        render?: boolean;
+        /**
+         * when true, the main error will possess a stack trace, otherwise it will be disabled.
+         * Defaults to false for performances reasons. Has no effect on platforms other than V8/node.js as it uses the Stack trace API.
+         *
+         * @default false
+         */
+        stack?: boolean;
+        /**
+         * overrides the way values are wrapped (e.g. `[]` arround arrays, `""` around labels).
+         * Each key can be set to a string with one (same character before and after the value) or two characters (first character
+         * before and second character after), or `false` to disable wrapping.
+         */
+        wrap?: {
+            /**
+             * the characters used around `{#label}` references. Defaults to `'"'`.
+             *
+             * @default '"'
+             */
+            label?: string | false,
+
+            /**
+             * the characters used around array avlues. Defaults to `'[]'`
+             *
+             * @default '[]'
+             */
+            array?: string | false
+        };
+    }
+
+    interface BaseValidationOptions {
+        /**
+         * when true, stops validation on the first error, otherwise returns all the errors found.
+         *
+         * @default true
+         */
+        abortEarly?: boolean;
+        /**
+         * when true, allows object to contain unknown keys which are ignored.
+         *
+         * @default false
+         */
+        allowUnknown?: boolean;
+        /**
+         * when true, schema caching is enabled (for schemas with explicit caching rules).
+         *
+         * @default false
+         */
+        cache?: boolean;
+        /**
+         * provides an external data set to be used in references
+         */
+        context?: Context;
+        /**
+         * when true, attempts to cast values to the required types (e.g. a string to a number).
+         *
+         * @default true
+         */
+        convert?: boolean;
+        /**
+         * sets the string format used when converting dates to strings in error messages and casting.
+         *
+         * @default 'iso'
+         */
+        dateFormat?: 'date' | 'iso' | 'string' | 'time' | 'utc';
+        /**
+         * when true, valid results and throw errors are decorated with a debug property which includes an array of the validation steps used to generate the returned result.
+         *
+         * @default false
+         */
+        debug?: boolean;
+        /**
+         * error formatting settings.
+         */
+        errors?: ErrorFormattingOptions;
+        /**
+         * if false, the external rules set with `any.external()` are ignored, which is required to ignore any external validations in synchronous mode (or an exception is thrown).
+         *
+         * @default true
+         */
+        externals?: boolean;
+        /**
+         * when true, do not apply default values.
+         *
+         * @default false
+         */
+        noDefaults?: boolean;
+        /**
+         * when true, inputs are shallow cloned to include non-enumerables properties.
+         *
+         * @default false
+         */
+        nonEnumerables?: boolean;
+        /**
+         * sets the default presence requirements. Supported modes: 'optional', 'required', and 'forbidden'.
+         *
+         * @default 'optional'
+         */
+        presence?: PresenceMode;
+        /**
+         * when true, ignores unknown keys with a function value.
+         *
+         * @default false
+         */
+        skipFunctions?: boolean;
+        /**
+         * remove unknown elements from objects and arrays.
+         * - when true, all unknown elements will be removed
+         * - when an object:
+         *      - objects - set to true to remove unknown keys from objects
+         *
+         * @default false
+         */
+        stripUnknown?: boolean | { arrays?: boolean; objects?: boolean };
+    }
+
+    interface ValidationOptions extends BaseValidationOptions {
+        /**
+         * overrides individual error messages. Defaults to no override (`{}`).
+         * Messages use the same rules as templates.
+         * Variables in double braces `{{var}}` are HTML escaped if the option `errors.escapeHtml` is set to true.
+         *
+         * @default {}
+         */
+        messages?: LanguageMessages;
+    }
+
+    interface AsyncValidationOptions extends ValidationOptions {
+        /**
+         * when true, warnings are returned alongside the value (i.e. `{ value, warning }`).
+         *
+         * @default false
+         */
+        warnings?: boolean;
+    }
+
+    interface LanguageMessageTemplate {
+        source: string;
+        rendered: string;
+    }
+
+    interface ErrorValidationOptions extends BaseValidationOptions {
+        messages?: Record<string, LanguageMessageTemplate>;
+    }
+
+    interface RenameOptions {
+        /**
+         * if true, does not delete the old key name, keeping both the new and old keys in place.
+         *
+         * @default false
+         */
+        alias?: boolean;
+        /**
+         * if true, allows renaming multiple keys to the same destination where the last rename wins.
+         *
+         * @default false
+         */
+        multiple?: boolean;
+        /**
+         * if true, allows renaming a key over an existing key.
+         *
+         * @default false
+         */
+        override?: boolean;
+        /**
+         * if true, skip renaming of a key if it's undefined.
+         *
+         * @default false
+         */
+        ignoreUndefined?: boolean;
+    }
+
+    interface TopLevelDomainOptions {
+        /**
+         * - `true` to use the IANA list of registered TLDs. This is the default value.
+         * - `false` to allow any TLD not listed in the `deny` list, if present.
+         * - A `Set` or array of the allowed TLDs. Cannot be used together with `deny`.
+         */
+        allow?: Set<string> | string[] | boolean;
+        /**
+         * - A `Set` or array of the forbidden TLDs. Cannot be used together with a custom `allow` list.
+         */
+        deny?: Set<string> | string[];
+    }
+
+    interface HierarchySeparatorOptions {
+        /**
+         * overrides the default `.` hierarchy separator. Set to false to treat the key as a literal value.
+         *
+         * @default '.'
+         */
+        separator?: string | false;
+    }
+
+    interface EmailOptions {
+        /**
+         * If `true`, Unicode characters are permitted
+         *
+         * @default true
+         */
+        allowUnicode?: boolean;
+        /**
+         * if `true`, ignore invalid email length errors.
+         *
+         * @default false
+         */
+        ignoreLength?: boolean;
+        /**
+         * if true, allows multiple email addresses in a single string, separated by , or the separator characters.
+         *
+         * @default false
+         */
+        multiple?: boolean;
+        /**
+         * when multiple is true, overrides the default , separator. String can be a single character or multiple separator characters.
+         *
+         * @default ','
+         */
+        separator?: string | string[];
+        /**
+         * Options for TLD (top level domain) validation. By default, the TLD must be a valid name listed on the [IANA registry](http://data.iana.org/TLD/tlds-alpha-by-domain.txt)
+         *
+         * @default { allow: true }
+         */
+        tlds?: TopLevelDomainOptions | false;
+        /**
+         * Number of segments required for the domain. Be careful since some domains, such as `io`, directly allow email.
+         *
+         * @default 2
+         */
+        minDomainSegments?: number;
+    }
+
+    interface DomainOptions {
+        /**
+         * If `true`, Unicode characters are permitted
+         *
+         * @default true
+         */
+        allowUnicode?: boolean;
+
+        /**
+         * Options for TLD (top level domain) validation. By default, the TLD must be a valid name listed on the [IANA registry](http://data.iana.org/TLD/tlds-alpha-by-domain.txt)
+         *
+         * @default { allow: true }
+         */
+        tlds?: TopLevelDomainOptions | false;
+        /**
+         * Number of segments required for the domain.
+         *
+         * @default 2
+         */
+        minDomainSegments?: number;
+    }
+
+    interface HexOptions {
+        /**
+         * hex decoded representation must be byte aligned.
+         * @default false
+         */
+        byteAligned?: boolean;
+    }
+
+    interface IpOptions {
+        /**
+         * One or more IP address versions to validate against. Valid values: ipv4, ipv6, ipvfuture
+         */
+        version?: string | string[];
+        /**
+         * Used to determine if a CIDR is allowed or not. Valid values: optional, required, forbidden
+         */
+        cidr?: PresenceMode;
+    }
+
+    type GuidVersions = 'uuidv1' | 'uuidv2' | 'uuidv3' | 'uuidv4' | 'uuidv5';
+
+    interface GuidOptions {
+        version: GuidVersions[] | GuidVersions;
+    }
+
+    interface UriOptions {
+        /**
+         * Specifies one or more acceptable Schemes, should only include the scheme name.
+         * Can be an Array or String (strings are automatically escaped for use in a Regular Expression).
+         */
+        scheme?: string | RegExp | Array<string | RegExp>;
+        /**
+         * Allow relative URIs.
+         *
+         * @default false
+         */
+        allowRelative?: boolean;
+        /**
+         * Restrict only relative URIs.
+         *
+         * @default false
+         */
+        relativeOnly?: boolean;
+        /**
+         * Allows unencoded square brackets inside the query string.
+         * This is NOT RFC 3986 compliant but query strings like abc[]=123&abc[]=456 are very common these days.
+         *
+         * @default false
+         */
+        allowQuerySquareBrackets?: boolean;
+        /**
+         * Validate the domain component using the options specified in `string.domain()`.
+         */
+        domain?: DomainOptions;
+    }
+
+    interface DataUriOptions {
+        /**
+         * optional parameter defaulting to true which will require `=` padding if true or make padding optional if false
+         *
+         * @default true
+         */
+        paddingRequired?: boolean;
+    }
+
+    interface Base64Options extends Pick<DataUriOptions, 'paddingRequired'> {
+        /**
+         * if true, uses the URI-safe base64 format which replaces `+` with `-` and `\` with `_`.
+         *
+         * @default false
+         */
+        urlSafe?: boolean;
+    }
+
+    interface SwitchCases {
+        /**
+         * the required condition joi type.
+         */
+        is: SchemaLike;
+        /**
+         * the alternative schema type if the condition is true.
+         */
+        then: SchemaLike;
+    }
+
+    interface SwitchDefault {
+        /**
+         * the alternative schema type if no cases matched.
+         * Only one otherwise statement is allowed in switch as the last array item.
+         */
+        otherwise: SchemaLike;
+    }
+
+    interface WhenOptions {
+        /**
+         * the required condition joi type.
+         */
+        is?: SchemaLike;
+
+        /**
+         * the negative version of `is` (`then` and `otherwise` have reverse
+         * roles).
+         */
+        not?: SchemaLike;
+
+        /**
+         * the alternative schema type if the condition is true. Required if otherwise or switch are missing.
+         */
+        then?: SchemaLike;
+
+        /**
+         * the alternative schema type if the condition is false. Required if then or switch are missing.
+         */
+        otherwise?: SchemaLike;
+
+        /**
+         * the list of cases. Required if then is missing.  Required if then or otherwise are missing.
+         */
+        switch?: Array<SwitchCases | SwitchDefault>;
+
+        /**
+         * whether to stop applying further conditions if the condition is true.
+         */
+        break?: boolean;
+    }
+
+    interface WhenSchemaOptions {
+        /**
+         * the alternative schema type if the condition is true. Required if otherwise is missing.
+         */
+        then?: SchemaLike;
+        /**
+         * the alternative schema type if the condition is false. Required if then is missing.
+         */
+        otherwise?: SchemaLike;
+    }
+
+    interface Cache {
+        /**
+         * Add an item to the cache.
+         *
+         * Note that key and value can be anything including objects, array, etc.
+         */
+        set(key: any, value: any): void;
+
+        /**
+         * Retrieve an item from the cache.
+         *
+         * Note that key and value can be anything including objects, array, etc.
+         */
+        get(key: any): any;
+    }
+    interface CacheProvisionOptions {
+        /**
+         * number of items to store in the cache before the least used items are dropped.
+         *
+         * @default 1000
+         */
+        max: number;
+    }
+
+    interface CacheConfiguration {
+        /**
+         * Provisions a simple LRU cache for caching simple inputs (`undefined`, `null`, strings, numbers, and booleans).
+         */
+        provision(options?: CacheProvisionOptions): void;
+    }
+
+    interface CompileOptions {
+        /**
+         * If true and the provided schema is (or contains parts) using an older version of joi, will return a compiled schema that is compatible with the older version.
+         * If false, the schema is always compiled using the current version and if older schema components are found, an error is thrown.
+         */
+        legacy: boolean;
+    }
+
+    interface IsSchemaOptions {
+        /**
+         * If true, will identify schemas from older versions of joi, otherwise will throw an error.
+         *
+         * @default false
+         */
+        legacy: boolean;
+    }
+
+    interface ReferenceOptions extends HierarchySeparatorOptions {
+        /**
+         * a function with the signature `function(value)` where `value` is the resolved reference value and the return value is the adjusted value to use.
+         * Note that the adjust feature will not perform any type validation on the adjusted value and it must match the value expected by the rule it is used in.
+         * Cannot be used with `map`.
+         *
+         * @example `(value) => value + 5`
+         */
+        adjust?: (value: any) => any;
+
+        /**
+         * an array of array pairs using the format `[[key, value], [key, value]]` used to maps the resolved reference value to another value.
+         * If the resolved value is not in the map, it is returned as-is.
+         * Cannot be used with `adjust`.
+         */
+        map?: Array<[any, any]>;
+
+        /**
+         * overrides default prefix characters.
+         */
+        prefix?: {
+            /**
+             * references to the globally provided context preference.
+             *
+             * @default '$'
+             */
+            global?: string;
+
+            /**
+             * references to error-specific or rule specific context.
+             *
+             * @default '#'
+             */
+            local?: string;
+
+            /**
+             * references to the root value being validated.
+             *
+             * @default '/'
+             */
+            root?: string;
+        };
+
+        /**
+         * If set to a number, sets the reference relative starting point.
+         * Cannot be combined with separator prefix characters.
+         * Defaults to the reference key prefix (or 1 if none present)
+         */
+        ancestor?: number;
+
+        /**
+         * creates an in-reference.
+         */
+        in?: boolean;
+
+        /**
+         * when true, the reference resolves by reaching into maps and sets.
+         */
+        iterables?: boolean;
+
+        /**
+         * when true, the value of the reference is used instead of its name in error messages 
+         * and template rendering. Defaults to false.
+         */
+        render?: boolean;
+    }
+
+    interface StringRegexOptions {
+        /**
+         * optional pattern name.
+         */
+        name?: string;
+
+        /**
+         * when true, the provided pattern will be disallowed instead of required.
+         *
+         * @default false
+         */
+        invert?: boolean;
+    }
+
+    interface RuleOptions {
+        /**
+         * if true, the rules will not be replaced by the same unique rule later.
+         *
+         * For example, `Joi.number().min(1).rule({ keep: true }).min(2)` will keep both `min()` rules instead of the later rule overriding the first.
+         *
+         * @default false
+         */
+        keep?: boolean;
+
+        /**
+         * a single message string or a messages object where each key is an error code and corresponding message string as value.
+         *
+         * The object is the same as the messages used as an option in `any.validate()`.
+         * The strings can be plain messages or a message template.
+         */
+        message?: string | LanguageMessages;
+
+        /**
+         * if true, turns any error generated by the ruleset to warnings.
+         */
+        warn?: boolean;
+    }
+
+    interface ErrorReport extends Error {
+        code: string;
+        flags: Record<string, ExtensionFlag>;
+        path: string[];
+        prefs: ErrorValidationOptions;
+        messages: LanguageMessages;
+        state: State;
+        value: any;
+    }
+
+    interface ValidationError extends Error {
+        name: 'ValidationError';
+
+        isJoi: boolean;
+
+        /**
+         * array of errors.
+         */
+        details: ValidationErrorItem[];
+
+        /**
+         * function that returns a string with an annotated version of the object pointing at the places where errors occurred.
+         *
+         * NOTE: This method does not exist in browser builds of Joi
+         *
+         * @param stripColors - if truthy, will strip the colors out of the output.
+         */
+        annotate(stripColors?: boolean): string;
+
+        _original: any;
+    }
+
+    interface ValidationErrorItem {
+        message: string;
+        path: Array<string | number>;
+        type: string;
+        context?: Context;
+    }
+
+    type ValidationErrorFunction = (errors: ErrorReport[]) => string | ValidationErrorItem | Error;
+
+    interface ValidationResult {
+        error?: ValidationError;
+        errors?: ValidationError;
+        warning?: ValidationError;
+        value: any;
+    }
+
+    interface CreateErrorOptions {
+        flags?: boolean;
+        messages?: LanguageMessages;
+    }
+
+    interface ModifyOptions {
+        each?: boolean;
+        once?: boolean;
+        ref?: boolean;
+        schema?: boolean;
+    }
+
+    interface MutateRegisterOptions {
+        family?: any;
+        key?: any;
+    }
+
+    interface SetFlagOptions {
+        clone: boolean;
+    }
+
+    interface CustomHelpers<V = any> {
+        schema: ExtensionBoundSchema;
+        state: State;
+        prefs: ValidationOptions;
+        original: V;
+        warn: (code: string, local?: Context) => void;
+        error: (code: string, local?: Context) => ErrorReport;
+        message: (messages: LanguageMessages, local?: Context) => ErrorReport;
+    }
+
+    type CustomValidator<V = any> = (value: V, helpers: CustomHelpers) => V | ErrorReport;
+
+    type ExternalValidationFunction = (value: any) => any;
+
+    type SchemaLikeWithoutArray = string | number | boolean | null | Schema | SchemaMap;
+    type SchemaLike = SchemaLikeWithoutArray | object;
+
+    type SchemaMap<TSchema = any> = {
+        [key in keyof TSchema]?: SchemaLike | SchemaLike[];
+    };
+
+    type Schema =
+        | AnySchema
+        | ArraySchema
+        | AlternativesSchema
+        | BinarySchema
+        | BooleanSchema
+        | DateSchema
+        | FunctionSchema
+        | NumberSchema
+        | ObjectSchema
+        | StringSchema
+        | LinkSchema
+        | SymbolSchema;
+
+    type SchemaFunction = (schema: Schema) => Schema;
+
+    interface AddRuleOptions {
+        name: string;
+        args?: {
+            [key: string]: any;
+        };
+    }
+
+    interface GetRuleOptions {
+        args?: Record<string, any>;
+        method?: string;
+        name: string;
+        operator?: string;
+    }
+
+    interface SchemaInternals {
+        /**
+         * Parent schema object.
+         */
+        $_super: Schema;
+
+        /**
+         * Terms of current schema.
+         */
+        $_terms: Record<string, any>;
+
+        /**
+         * Adds a rule to current validation schema.
+         */
+        $_addRule(rule: string | AddRuleOptions): Schema;
+
+        /**
+         * Internally compiles schema.
+         */
+        $_compile(schema: SchemaLike, options?: CompileOptions): Schema;
+
+        /**
+         * Creates a joi error object.
+         */
+        $_createError(
+            code: string,
+            value: any,
+            context: Context,
+            state: State,
+            prefs: ValidationOptions,
+            options?: CreateErrorOptions,
+        ): Err;
+
+        /**
+         * Get value from given flag.
+         */
+        $_getFlag(name: string): any;
+
+        /**
+         * Retrieve some rule configuration.
+         */
+        $_getRule(name: string): GetRuleOptions | undefined;
+
+        $_mapLabels(path: string | string[]): string;
+
+        /**
+         * Returns true if validations runs fine on given value.
+         */
+        $_match(value: any, state: State, prefs: ValidationOptions): boolean;
+
+        $_modify(options?: ModifyOptions): Schema;
+
+        /**
+         * Resets current schema.
+         */
+        $_mutateRebuild(): this;
+
+        $_mutateRegister(schema: Schema, options?: MutateRegisterOptions): void;
+
+        /**
+         * Get value from given property.
+         */
+        $_property(name: string): any;
+
+        /**
+         * Get schema at given path.
+         */
+        $_reach(path: string[]): Schema;
+
+        /**
+         * Get current schema root references.
+         */
+        $_rootReferences(): any;
+
+        /**
+         * Set flag to given value.
+         */
+        $_setFlag(flag: string, value: any, options?: SetFlagOptions): void;
+
+        /**
+         * Runs internal validations against given value.
+         */
+        $_validate(value: any, state: State, prefs: ValidationOptions): ValidationResult;
+    }
+
+    interface AnySchema extends SchemaInternals {
+        /**
+         * Flags of current schema.
+         */
+        _flags: Record<string, any>;
+
+        /**
+         * Starts a ruleset in order to apply multiple rule options. The set ends when `rule()`, `keep()`, `message()`, or `warn()` is called.
+         */
+        $: this;
+
+        /**
+         * Starts a ruleset in order to apply multiple rule options. The set ends when `rule()`, `keep()`, `message()`, or `warn()` is called.
+         */
+        ruleset: this;
+
+        type?: Types | string;
+
+        /**
+         * Whitelists a value
+         */
+        allow(...values: any[]): this;
+
+        /**
+         * Assign target alteration options to a schema that are applied when `any.tailor()` is called.
+         * @param targets - an object where each key is a target name, and each value is a function that takes an schema and returns an schema.
+         */
+        alter(targets: Record<string, SchemaFunction>): this;
+
+        /**
+         * By default, some Joi methods to function properly need to rely on the Joi instance they are attached to because
+         * they use `this` internally.
+         * So `Joi.string()` works but if you extract the function from it and call `string()` it won't.
+         * `bind()` creates a new Joi instance where all the functions relying on `this` are bound to the Joi instance.
+         */
+        bind(): this;
+
+        /**
+         * Adds caching to the schema which will attempt to cache the validation results (success and failures) of incoming inputs.
+         * If no cache is passed, a default cache is provisioned by using `cache.provision()` internally.
+         */
+        cache(cache?: Cache): this;
+
+        /**
+         * Casts the validated value to the specified type.
+         */
+        cast(to: 'map' | 'number' | 'set' | 'string'): this;
+
+        /**
+         * Returns a new type that is the result of adding the rules of one type to another.
+         */
+        concat(schema: this): this;
+
+        /**
+         * Adds a custom validation function.
+         */
+        custom(fn: CustomValidator, description?: string): this;
+
+        /**
+         * Sets a default value if the original value is `undefined` where:
+         * @param value - the default value. One of:
+         *    - a literal value (string, number, object, etc.)
+         *    - a [references](#refkey-options)
+         *    - a function which returns the default value using the signature `function(parent, helpers)` where:
+         *        - `parent` - a clone of the object containing the value being validated. Note that since specifying a
+         *          `parent` ragument performs cloning, do not declare format arguments if you are not using them.
+         *        - `helpers` - same as thsoe described in [`any.custom()`](anycustomermethod_description)
+         *
+         * When called without any `value` on an object schema type, a default value will be automatically generated
+         * based on the default values of the object keys.
+         *
+         * Note that if value is an object, any changes to the object after `default()` is called will change the
+         *  reference and any future assignment.
+         */
+        default(value?: BasicType | Reference | ((parent: any, helpers: CustomHelpers) => BasicType | Reference)): this;
+
+        /**
+         * Returns a plain object representing the schema's rules and properties
+         */
+        describe(): Description;
+
+        /**
+         * Annotates the key
+         */
+        description(desc: string): this;
+
+        /**
+         * Disallows values.
+         */
+        disallow(...values: any[]): this;
+
+        /**
+         * Considers anything that matches the schema to be empty (undefined).
+         * @param schema - any object or joi schema to match. An undefined schema unsets that rule.
+         */
+        empty(schema?: SchemaLike): this;
+
+        /**
+         * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed.
+         */
+        equal(...values: any[]): this;
+
+        /**
+         * Overrides the default joi error with a custom error if the rule fails where:
+         * @param err - can be:
+         *   an instance of `Error` - the override error.
+         *   a `function(errors)`, taking an array of errors as argument, where it must either:
+         *    return a `string` - substitutes the error message with this text
+         *    return a single ` object` or an `Array` of it, where:
+         *     `type` - optional parameter providing the type of the error (eg. `number.min`).
+         *     `message` - optional parameter if `template` is provided, containing the text of the error.
+         *     `template` - optional parameter if `message` is provided, containing a template string, using the same format as usual joi language errors.
+         *     `context` - optional parameter, to provide context to your error if you are using the `template`.
+         *    return an `Error` - same as when you directly provide an `Error`, but you can customize the error message based on the errors.
+         *
+         * Note that if you provide an `Error`, it will be returned as-is, unmodified and undecorated with any of the
+         * normal joi error properties. If validation fails and another error is found before the error
+         * override, that error will be returned and the override will be ignored (unless the `abortEarly`
+         * option has been set to `false`).
+         */
+        error(err: Error | ValidationErrorFunction): this;
+
+        /**
+         * Annotates the key with an example value, must be valid.
+         */
+        example(value: any, options?: { override: boolean }): this;
+
+        /**
+         * Marks a key as required which will not allow undefined as value. All keys are optional by default.
+         */
+        exist(): this;
+
+        /**
+         * Adds an external validation rule.
+         *
+         * Note that external validation rules are only called after the all other validation rules for the entire schema (from the value root) are checked.
+         * This means that any changes made to the value by the external rules are not available to any other validation rules during the non-external validation phase.
+         * If schema validation failed, no external validation rules are called.
+         */
+        external(method: ExternalValidationFunction, description?: string): this;
+
+        /**
+         * Returns a sub-schema based on a path of object keys or schema ids.
+         *
+         * @param path - a dot `.` separated path string or a pre-split array of path keys. The keys must match the sub-schema id or object key (if no id was explicitly set).
+         */
+        extract(path: string | string[]): Schema;
+
+        /**
+         * Sets a failover value if the original value fails passing validation.
+         *
+         * @param value - the failover value. value supports references. value may be assigned a function which returns the default value.
+         *
+         * If value is specified as a function that accepts a single parameter, that parameter will be a context object that can be used to derive the resulting value.
+         * Note that if value is an object, any changes to the object after `failover()` is called will change the reference and any future assignment.
+         * Use a function when setting a dynamic value (e.g. the current time).
+         * Using a function with a single argument performs some internal cloning which has a performance impact.
+         * If you do not need access to the context, define the function without any arguments.
+         */
+        failover(value: any): this;
+
+        /**
+         * Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys.
+         */
+        forbidden(): this;
+
+        /**
+         * Returns a new schema where each of the path keys listed have been modified.
+         *
+         * @param key - an array of key strings, a single key string, or an array of arrays of pre-split key strings.
+         * @param adjuster - a function which must return a modified schema.
+         */
+        fork(key: string | string[] | string[][], adjuster: SchemaFunction): this;
+
+        /**
+         * Sets a schema id for reaching into the schema via `any.extract()`.
+         * If no id is set, the schema id defaults to the object key it is associated with.
+         * If the schema is used in an array or alternatives type and no id is set, the schema in unreachable.
+         */
+        id(name?: string): this;
+
+        /**
+         * Disallows values.
+         */
+        invalid(...values: any[]): this;
+
+        /**
+         * Same as `rule({ keep: true })`.
+         *
+         * Note that `keep()` will terminate the current ruleset and cannot be followed by another rule option.
+         * Use `rule()` to apply multiple rule options.
+         */
+        keep(): this;
+
+        /**
+         * Overrides the key name in error messages.
+         */
+        label(name: string): this;
+
+        /**
+         * Same as `rule({ message })`.
+         *
+         * Note that `message()` will terminate the current ruleset and cannot be followed by another rule option.
+         * Use `rule()` to apply multiple rule options.
+         */
+        message(message: string): this;
+
+        /**
+         * Same as `any.prefs({ messages })`.
+         * Note that while `any.message()` applies only to the last rule or ruleset, `any.messages()` applies to the entire schema.
+         */
+        messages(messages: LanguageMessages): this;
+
+        /**
+         * Attaches metadata to the key.
+         */
+        meta(meta: object): this;
+
+        /**
+         * Disallows values.
+         */
+        not(...values: any[]): this;
+
+        /**
+         * Annotates the key
+         */
+        note(...notes: string[]): this;
+
+        /**
+         * Requires the validated value to match of the provided `any.allow()` values.
+         * It has not effect when called together with `any.valid()` since it already sets the requirements.
+         * When used with `any.allow()` it converts it to an `any.valid()`.
+         */
+        only(): this;
+
+        /**
+         * Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default.
+         */
+        optional(): this;
+
+        /**
+         * Overrides the global validate() options for the current key and any sub-key.
+         */
+        options(options: ValidationOptions): this;
+
+        /**
+         * Overrides the global validate() options for the current key and any sub-key.
+         */
+        prefs(options: ValidationOptions): this;
+
+        /**
+         * Overrides the global validate() options for the current key and any sub-key.
+         */
+        preferences(options: ValidationOptions): this;
+
+        /**
+         * Sets the presence mode for the schema.
+         */
+        presence(mode: PresenceMode): this;
+
+        /**
+         * Outputs the original untouched value instead of the casted value.
+         */
+        raw(enabled?: boolean): this;
+
+        /**
+         * Marks a key as required which will not allow undefined as value. All keys are optional by default.
+         */
+        required(): this;
+
+        /**
+         * Applies a set of rule options to the current ruleset or last rule added.
+         *
+         * When applying rule options, the last rule (e.g. `min()`) is used unless there is an active ruleset defined (e.g. `$.min().max()`)
+         * in which case the options are applied to all the provided rules.
+         * Once `rule()` is called, the previous rules can no longer be modified and any active ruleset is terminated.
+         *
+         * Rule modifications can only be applied to supported rules.
+         * Most of the `any` methods do not support rule modifications because they are implemented using schema flags (e.g. `required()`) or special
+         * internal implementation (e.g. `valid()`).
+         * In those cases, use the `any.messages()` method to override the error codes for the errors you want to customize.
+         */
+        rule(options: RuleOptions): this;
+
+        /**
+         * Registers a schema to be used by decendents of the current schema in named link references.
+         */
+        shared(ref: Schema): this;
+
+        /**
+         * Sets the options.convert options to false which prevent type casting for the current key and any child keys.
+         */
+        strict(isStrict?: boolean): this;
+
+        /**
+         * Marks a key to be removed from a resulting object or array after validation. Used to sanitize output.
+         * @param [enabled=true] - if true, the value is stripped, otherwise the validated value is retained. Defaults to true.
+         */
+        strip(enabled?: boolean): this;
+
+        /**
+         * Annotates the key
+         */
+        tag(...tags: string[]): this;
+
+        /**
+         * Applies any assigned target alterations to a copy of the schema that were applied via `any.alter()`.
+         */
+        tailor(targets: string | string[]): Schema;
+
+        /**
+         * Annotates the key with an unit name.
+         */
+        unit(name: string): this;
+
+        /**
+         * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed.
+         */
+        valid(...values: any[]): this;
+
+        /**
+         * Validates a value using the schema and options.
+         */
+        validate(value: any, options?: ValidationOptions): ValidationResult;
+
+        /**
+         * Validates a value using the schema and options.
+         */
+        validateAsync(value: any, options?: AsyncValidationOptions): Promise<any>;
+
+        /**
+         * Same as `rule({ warn: true })`.
+         * Note that `warn()` will terminate the current ruleset and cannot be followed by another rule option.
+         * Use `rule()` to apply multiple rule options.
+         */
+        warn(): this;
+
+        /**
+         * Generates a warning.
+         * When calling `any.validateAsync()`, set the `warning` option to true to enable warnings.
+         * Warnings are reported separately from errors alongside the result value via the warning key (i.e. `{ value, warning }`).
+         * Warning are always included when calling `any.validate()`.
+         */
+        warning(code: string, context: Context): this;
+
+        /**
+         * Converts the type into an alternatives type where the conditions are merged into the type definition where:
+         */
+        when(ref: string | Reference, options: WhenOptions): this;
+
+        /**
+         * Converts the type into an alternatives type where the conditions are merged into the type definition where:
+         */
+        when(ref: Schema, options: WhenSchemaOptions): this;
+    }
+
+    interface Description {
+        type?: Types | string;
+        label?: string;
+        description?: string;
+        flags?: object;
+        notes?: string[];
+        tags?: string[];
+        meta?: any[];
+        example?: any[];
+        valids?: any[];
+        invalids?: any[];
+        unit?: string;
+        options?: ValidationOptions;
+        [key: string]: any;
+    }
+
+    interface Context {
+        [key: string]: any;
+        key?: string;
+        label?: string;
+        value?: any;
+    }
+
+    interface State {
+        key?: string;
+        path?: string;
+        parent?: any;
+        reference?: any;
+        ancestors?: any;
+        localize?(...args: any[]): State;
+    }
+
+    interface BooleanSchema extends AnySchema {
+        /**
+         * Allows for additional values to be considered valid booleans by converting them to false during validation.
+         * String comparisons are by default case insensitive,
+         * see `boolean.sensitive()` to change this behavior.
+         * @param values - strings, numbers or arrays of them
+         */
+        falsy(...values: Array<string | number>): this;
+
+        /**
+         * Allows the values provided to truthy and falsy as well as the "true" and "false" default conversion
+         * (when not in `strict()` mode) to be matched in a case insensitive manner.
+         */
+        sensitive(enabled?: boolean): this;
+
+        /**
+         * Allows for additional values to be considered valid booleans by converting them to true during validation.
+         * String comparisons are by default case insensitive, see `boolean.sensitive()` to change this behavior.
+         * @param values - strings, numbers or arrays of them
+         */
+        truthy(...values: Array<string | number>): this;
+    }
+
+    interface NumberSchema extends AnySchema {
+        /**
+         * Specifies that the value must be greater than limit.
+         * It can also be a reference to another field.
+         */
+        greater(limit: number | Reference): this;
+
+        /**
+         * Requires the number to be an integer (no floating point).
+         */
+        integer(): this;
+
+        /**
+         * Specifies that the value must be less than limit.
+         * It can also be a reference to another field.
+         */
+        less(limit: number | Reference): this;
+
+        /**
+         * Specifies the maximum value.
+         * It can also be a reference to another field.
+         */
+        max(limit: number | Reference): this;
+
+        /**
+         * Specifies the minimum value.
+         * It can also be a reference to another field.
+         */
+        min(limit: number | Reference): this;
+
+        /**
+         * Specifies that the value must be a multiple of base.
+         */
+        multiple(base: number | Reference): this;
+
+        /**
+         * Requires the number to be negative.
+         */
+        negative(): this;
+
+        /**
+         * Requires the number to be a TCP port, so between 0 and 65535.
+         */
+        port(): this;
+
+        /**
+         * Requires the number to be positive.
+         */
+        positive(): this;
+
+        /**
+         * Specifies the maximum number of decimal places where:
+         * @param limit - the maximum number of decimal places allowed.
+         */
+        precision(limit: number): this;
+
+        /**
+         * Requires the number to be negative or positive.
+         */
+        sign(sign: 'positive' | 'negative'): this;
+
+        /**
+         * Allows the number to be outside of JavaScript's safety range (Number.MIN_SAFE_INTEGER & Number.MAX_SAFE_INTEGER).
+         */
+        unsafe(enabled?: any): this;
+    }
+
+    interface StringSchema extends AnySchema {
+        /**
+         * Requires the string value to only contain a-z, A-Z, and 0-9.
+         */
+        alphanum(): this;
+
+        /**
+         * Requires the string value to be a valid base64 string; does not check the decoded value.
+         */
+        base64(options?: Base64Options): this;
+
+        /**
+         * Sets the required string case.
+         */
+        case(direction: 'upper' | 'lower'): this;
+
+        /**
+         * Requires the number to be a credit card number (Using Lunh Algorithm).
+         */
+        creditCard(): this;
+
+        /**
+         * Requires the string value to be a valid data URI string.
+         */
+        dataUri(options?: DataUriOptions): this;
+
+        /**
+         * Requires the string value to be a valid domain.
+         */
+        domain(options?: DomainOptions): this;
+
+        /**
+         * Requires the string value to be a valid email address.
+         */
+        email(options?: EmailOptions): this;
+
+        /**
+         * Requires the string value to be a valid GUID.
+         */
+        guid(options?: GuidOptions): this;
+
+        /**
+         * Requires the string value to be a valid hexadecimal string.
+         */
+        hex(options?: HexOptions): this;
+
+        /**
+         * Requires the string value to be a valid hostname as per RFC1123.
+         */
+        hostname(): this;
+
+        /**
+         * Allows the value to match any whitelist of blacklist item in a case insensitive comparison.
+         */
+        insensitive(): this;
+
+        /**
+         * Requires the string value to be a valid ip address.
+         */
+        ip(options?: IpOptions): this;
+
+        /**
+         * Requires the string value to be in valid ISO 8601 date format.
+         */
+        isoDate(): this;
+
+        /**
+         * Requires the string value to be in valid ISO 8601 duration format.
+         */
+        isoDuration(): this;
+
+        /**
+         * Specifies the exact string length required
+         * @param limit - the required string length. It can also be a reference to another field.
+         * @param encoding - if specified, the string length is calculated in bytes using the provided encoding.
+         */
+        length(limit: number | Reference, encoding?: string): this;
+
+        /**
+         * Requires the string value to be all lowercase. If the validation convert option is on (enabled by default), the string will be forced to lowercase.
+         */
+        lowercase(): this;
+
+        /**
+         * Specifies the maximum number of string characters.
+         * @param limit - the maximum number of string characters allowed. It can also be a reference to another field.
+         * @param encoding - if specified, the string length is calculated in bytes using the provided encoding.
+         */
+        max(limit: number | Reference, encoding?: string): this;
+
+        /**
+         * Specifies the minimum number string characters.
+         * @param limit - the minimum number of string characters required. It can also be a reference to another field.
+         * @param encoding - if specified, the string length is calculated in bytes using the provided encoding.
+         */
+        min(limit: number | Reference, encoding?: string): this;
+
+        /**
+         * Requires the string value to be in a unicode normalized form. If the validation convert option is on (enabled by default), the string will be normalized.
+         * @param [form='NFC'] - The unicode normalization form to use. Valid values: NFC [default], NFD, NFKC, NFKD
+         */
+        normalize(form?: 'NFC' | 'NFD' | 'NFKC' | 'NFKD'): this;
+
+        /**
+         * Defines a regular expression rule.
+         * @param pattern - a regular expression object the string value must match against.
+         * @param options - optional, can be:
+         *   Name for patterns (useful with multiple patterns). Defaults to 'required'.
+         *   An optional configuration object with the following supported properties:
+         *     name - optional pattern name.
+         *     invert - optional boolean flag. Defaults to false behavior. If specified as true, the provided pattern will be disallowed instead of required.
+         */
+        pattern(pattern: RegExp, options?: string | StringRegexOptions): this;
+
+        /**
+         * Defines a regular expression rule.
+         * @param pattern - a regular expression object the string value must match against.
+         * @param options - optional, can be:
+         *   Name for patterns (useful with multiple patterns). Defaults to 'required'.
+         *   An optional configuration object with the following supported properties:
+         *     name - optional pattern name.
+         *     invert - optional boolean flag. Defaults to false behavior. If specified as true, the provided pattern will be disallowed instead of required.
+         */
+        regex(pattern: RegExp, options?: string | StringRegexOptions): this;
+
+        /**
+         * Replace characters matching the given pattern with the specified replacement string where:
+         * @param pattern - a regular expression object to match against, or a string of which all occurrences will be replaced.
+         * @param replacement - the string that will replace the pattern.
+         */
+        replace(pattern: RegExp | string, replacement: string): this;
+
+        /**
+         * Requires the string value to only contain a-z, A-Z, 0-9, and underscore _.
+         */
+        token(): this;
+
+        /**
+         * Requires the string value to contain no whitespace before or after. If the validation convert option is on (enabled by default), the string will be trimmed.
+         * @param [enabled=true] - optional parameter defaulting to true which allows you to reset the behavior of trim by providing a falsy value.
+         */
+        trim(enabled?: any): this;
+
+        /**
+         * Specifies whether the string.max() limit should be used as a truncation.
+         * @param [enabled=true] - optional parameter defaulting to true which allows you to reset the behavior of truncate by providing a falsy value.
+         */
+        truncate(enabled?: boolean): this;
+
+        /**
+         * Requires the string value to be all uppercase. If the validation convert option is on (enabled by default), the string will be forced to uppercase.
+         */
+        uppercase(): this;
+
+        /**
+         * Requires the string value to be a valid RFC 3986 URI.
+         */
+        uri(options?: UriOptions): this;
+
+        /**
+         * Requires the string value to be a valid GUID.
+         */
+        uuid(options?: GuidOptions): this;
+    }
+
+    interface SymbolSchema extends AnySchema {
+        // TODO: support number and symbol index
+        map(iterable: Iterable<[string | number | boolean | symbol, symbol]> | { [key: string]: symbol }): this;
+    }
+
+    interface ArraySortOptions {
+        /**
+         * @default 'ascending'
+         */
+        order?: 'ascending' | 'descending';
+        by?: string | Reference;
+    }
+
+    interface ArrayUniqueOptions extends HierarchySeparatorOptions {
+        /**
+         * if true, undefined values for the dot notation string comparator will not cause the array to fail on uniqueness.
+         *
+         * @default false
+         */
+        ignoreUndefined?: boolean;
+    }
+
+    type ComparatorFunction = (a: any, b: any) => boolean;
+
+    interface ArraySchema extends AnySchema {
+        /**
+         * Verifies that an assertion passes for at least one item in the array, where:
+         * `schema` - the validation rules required to satisfy the assertion. If the `schema` includes references, they are resolved against
+         * the array item being tested, not the value of the `ref` target.
+         */
+        has(schema: SchemaLike): this;
+
+        /**
+         * List the types allowed for the array values.
+         * If a given type is .required() then there must be a matching item in the array.
+         * If a type is .forbidden() then it cannot appear in the array.
+         * Required items can be added multiple times to signify that multiple items must be found.
+         * Errors will contain the number of items that didn't match.
+         * Any unmatched item having a label will be mentioned explicitly.
+         *
+         * @param type - a joi schema object to validate each array item against.
+         */
+        items(...types: SchemaLikeWithoutArray[]): this;
+
+        /**
+         * Specifies the exact number of items in the array.
+         */
+        length(limit: number | Reference): this;
+
+        /**
+         * Specifies the maximum number of items in the array.
+         */
+        max(limit: number | Reference): this;
+
+        /**
+         * Specifies the minimum number of items in the array.
+         */
+        min(limit: number | Reference): this;
+
+        /**
+         * Lists the types in sequence order for the array values where:
+         * @param type - a joi schema object to validate against each array item in sequence order. type can be multiple values passed as individual arguments.
+         * If a given type is .required() then there must be a matching item with the same index position in the array.
+         * Errors will contain the number of items that didn't match.
+         * Any unmatched item having a label will be mentioned explicitly.
+         */
+        ordered(...types: SchemaLikeWithoutArray[]): this;
+
+        /**
+         * Allow single values to be checked against rules as if it were provided as an array.
+         * enabled can be used with a falsy value to go back to the default behavior.
+         */
+        single(enabled?: any): this;
+
+        /**
+         * Sorts the array by given order.
+         */
+        sort(options?: ArraySortOptions): this;
+
+        /**
+         * Allow this array to be sparse.
+         * enabled can be used with a falsy value to go back to the default behavior.
+         */
+        sparse(enabled?: any): this;
+
+        /**
+         * Requires the array values to be unique.
+         * Remember that if you provide a custom comparator function,
+         * different types can be passed as parameter depending on the rules you set on items.
+         * Be aware that a deep equality is performed on elements of the array having a type of object,
+         * a performance penalty is to be expected for this kind of operation.
+         */
+        unique(comparator?: string | ComparatorFunction, options?: ArrayUniqueOptions): this;
+    }
+
+    interface ObjectPatternOptions {
+        fallthrough?: boolean;
+        matches: SchemaLike | Reference;
+    }
+
+    interface ObjectSchema<TSchema = any> extends AnySchema {
+        /**
+         * Defines an all-or-nothing relationship between keys where if one of the peers is present, all of them are required as well.
+         *
+         * Optional settings must be the last argument.
+         */
+        and(...peers: Array<string | HierarchySeparatorOptions>): this;
+
+        /**
+         * Appends the allowed object keys. If schema is null, undefined, or {}, no changes will be applied.
+         */
+        append(schema?: SchemaMap<TSchema>): this;
+
+        /**
+         * Verifies an assertion where.
+         */
+        assert(ref: string | Reference, schema: SchemaLike, message?: string): this;
+
+        /**
+         * Requires the object to be an instance of a given constructor.
+         *
+         * @param constructor - the constructor function that the object must be an instance of.
+         * @param name - an alternate name to use in validation errors. This is useful when the constructor function does not have a name.
+         */
+        // tslint:disable-next-line:ban-types
+        instance(constructor: Function, name?: string): this;
+
+        /**
+         * Sets or extends the allowed object keys.
+         */
+        keys(schema?: SchemaMap<TSchema>): this;
+
+        /**
+         * Specifies the exact number of keys in the object.
+         */
+        length(limit: number): this;
+
+        /**
+         * Specifies the maximum number of keys in the object.
+         */
+        max(limit: number | Reference): this;
+
+        /**
+         * Specifies the minimum number of keys in the object.
+         */
+        min(limit: number | Reference): this;
+
+        /**
+         * Defines a relationship between keys where not all peers can be present at the same time.
+         *
+         * Optional settings must be the last argument.
+         */
+        nand(...peers: Array<string | HierarchySeparatorOptions>): this;
+
+        /**
+         * Defines a relationship between keys where one of the peers is required (and more than one is allowed).
+         *
+         * Optional settings must be the last argument.
+         */
+        or(...peers: Array<string | HierarchySeparatorOptions>): this;
+
+        /**
+         * Defines an exclusive relationship between a set of keys where only one is allowed but none are required.
+         *
+         * Optional settings must be the last argument.
+         */
+        oxor(...peers: Array<string | HierarchySeparatorOptions>): this;
+
+        /**
+         * Specify validation rules for unknown keys matching a pattern.
+         *
+         * @param pattern - a pattern that can be either a regular expression or a joi schema that will be tested against the unknown key names
+         * @param schema - the schema object matching keys must validate against
+         */
+        pattern(pattern: RegExp | SchemaLike, schema: SchemaLike, options?: ObjectPatternOptions): this;
+
+        /**
+         * Requires the object to be a Joi reference.
+         */
+        ref(): this;
+
+        /**
+         * Requires the object to be a `RegExp` object.
+         */
+        regex(): this;
+
+        /**
+         * Renames a key to another name (deletes the renamed key).
+         */
+        rename(from: string | RegExp, to: string, options?: RenameOptions): this;
+
+        /**
+         * Requires the object to be a Joi schema instance.
+         */
+        schema(type?: SchemaLike): this;
+
+        /**
+         * Overrides the handling of unknown keys for the scope of the current object only (does not apply to children).
+         */
+        unknown(allow?: boolean): this;
+
+        /**
+         * Requires the presence of other keys whenever the specified key is present.
+         */
+        with(key: string, peers: string | string[], options?: HierarchySeparatorOptions): this;
+
+        /**
+         * Forbids the presence of other keys whenever the specified is present.
+         */
+        without(key: string, peers: string | string[], options?: HierarchySeparatorOptions): this;
+
+        /**
+         * Defines an exclusive relationship between a set of keys. one of them is required but not at the same time.
+         *
+         * Optional settings must be the last argument.
+         */
+        xor(...peers: Array<string | HierarchySeparatorOptions>): this;
+    }
+
+    interface BinarySchema extends AnySchema {
+        /**
+         * Sets the string encoding format if a string input is converted to a buffer.
+         */
+        encoding(encoding: string): this;
+
+        /**
+         * Specifies the minimum length of the buffer.
+         */
+        min(limit: number | Reference): this;
+
+        /**
+         * Specifies the maximum length of the buffer.
+         */
+        max(limit: number | Reference): this;
+
+        /**
+         * Specifies the exact length of the buffer:
+         */
+        length(limit: number | Reference): this;
+    }
+
+    interface DateSchema extends AnySchema {
+        /**
+         * Specifies that the value must be greater than date.
+         * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date,
+         * allowing to explicitly ensure a date is either in the past or in the future.
+         * It can also be a reference to another field.
+         */
+        greater(date: 'now' | Date | number | string | Reference): this;
+
+        /**
+         * Requires the string value to be in valid ISO 8601 date format.
+         */
+        iso(): this;
+
+        /**
+         * Specifies that the value must be less than date.
+         * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date,
+         * allowing to explicitly ensure a date is either in the past or in the future.
+         * It can also be a reference to another field.
+         */
+        less(date: 'now' | Date | number | string | Reference): this;
+
+        /**
+         * Specifies the oldest date allowed.
+         * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date,
+         * allowing to explicitly ensure a date is either in the past or in the future.
+         * It can also be a reference to another field.
+         */
+        min(date: 'now' | Date | number | string | Reference): this;
+
+        /**
+         * Specifies the latest date allowed.
+         * Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date,
+         * allowing to explicitly ensure a date is either in the past or in the future.
+         * It can also be a reference to another field.
+         */
+        max(date: 'now' | Date | number | string | Reference): this;
+
+        /**
+         * Requires the value to be a timestamp interval from Unix Time.
+         * @param type - the type of timestamp (allowed values are unix or javascript [default])
+         */
+        timestamp(type?: 'javascript' | 'unix'): this;
+    }
+
+    interface FunctionSchema extends ObjectSchema {
+        /**
+         * Specifies the arity of the function where:
+         * @param n - the arity expected.
+         */
+        arity(n: number): this;
+
+        /**
+         * Requires the function to be a class.
+         */
+        class(): this;
+
+        /**
+         * Specifies the minimal arity of the function where:
+         * @param n - the minimal arity expected.
+         */
+        minArity(n: number): this;
+
+        /**
+         * Specifies the minimal arity of the function where:
+         * @param n - the minimal arity expected.
+         */
+        maxArity(n: number): this;
+    }
+
+    interface AlternativesSchema extends AnySchema {
+        /**
+         * Adds a conditional alternative schema type, either based on another key value, or a schema peeking into the current value.
+         */
+        conditional(ref: string | Reference, options: WhenOptions): this;
+        conditional(ref: Schema, options: WhenSchemaOptions): this;
+
+        /**
+         * Requires the validated value to match a specific set of the provided alternative.try() schemas.
+         * Cannot be combined with `alternatives.conditional()`.
+         */
+        match(mode: 'any' | 'all' | 'one'): this;
+
+        /**
+         * Adds an alternative schema type for attempting to match against the validated value.
+         */
+        try(...types: SchemaLikeWithoutArray[]): this;
+    }
+
+    interface LinkSchema extends AnySchema {
+        /**
+         * Same as `any.concat()` but the schema is merged after the link is resolved which allows merging with schemas of the same type as the resolved link.
+         * Will throw an exception during validation if the merged types are not compatible.
+         */
+        concat(schema: Schema): this;
+
+        /**
+         * Initializes the schema after constructions for cases where the schema has to be constructed first and then initialized.
+         * If `ref` was not passed to the constructor, `link.ref()` must be called prior to usaged.
+         */
+        ref(ref: string): this;
+    }
+
+    interface Reference extends Exclude<ReferenceOptions, 'prefix'> {
+        depth: number;
+        type: string;
+        key: string;
+        root: string;
+        path: string[];
+        display: string;
+        toString(): string;
+    }
+
+    type ExtensionBoundSchema = Schema & SchemaInternals;
+
+    interface RuleArgs {
+        name: string;
+        ref?: boolean;
+        assert?: ((value: any) => boolean) | AnySchema;
+        message?: string;
+
+        /**
+         * Undocumented properties
+         */
+        normalize?(value: any): any;
+    }
+
+    type RuleMethod = (...args: any[]) => any;
+
+    interface ExtensionRule {
+        /**
+         * alternative name for this rule.
+         */
+        alias?: string;
+        /**
+         * whether rule supports multiple invocations.
+         */
+        multi?: boolean;
+        /**
+         * Dual rule: converts or validates.
+         */
+        convert?: boolean;
+        /**
+         * list of arguments accepted by `method`.
+         */
+        args?: Array<RuleArgs | string>;
+        /**
+         * rule body.
+         */
+        method?: RuleMethod | false;
+        /**
+         * validation function.
+         */
+        validate?(value: any, helpers: any, args: Record<string, any>, options: any): any;
+
+        /**
+         * undocumented flags.
+         */
+        priority?: boolean;
+        manifest?: boolean;
+    }
+
+    interface CoerceResult {
+        errors?: ErrorReport[];
+        value?: any;
+    }
+
+    type CoerceFunction = (value: any, helpers: CustomHelpers) => CoerceResult;
+
+    interface CoerceObject {
+        method: CoerceFunction;
+        from?: string | string[];
+    }
+
+    interface ExtensionFlag {
+        setter?: string;
+        default?: any;
+    }
+
+    interface ExtensionTermManifest {
+        mapped: {
+            from: string;
+            to: string;
+        };
+    }
+
+    interface ExtensionTerm {
+        init: any[] | null;
+        register?: any;
+        manifest?: Record<string, 'schema' | 'single' | ExtensionTermManifest>;
+    }
+
+    interface Extension {
+        type: string | RegExp;
+        args?(...args: SchemaLike[]): Schema;
+        base?: Schema;
+        coerce?: CoerceFunction | CoerceObject;
+        flags?: Record<string, ExtensionFlag>;
+        manifest?: {
+            build?(obj: ExtensionBoundSchema, desc: Record<string, any>): any;
+        };
+        messages?: LanguageMessages | string;
+        modifiers?: Record<string, (rule: any, enabled?: boolean) => any>;
+        overrides?: Record<string, (value: any) => Schema>;
+        prepare?(value: any, helpers: CustomHelpers): any;
+        rebuild?(schema: ExtensionBoundSchema): void;
+        rules?: Record<string, ExtensionRule & ThisType<SchemaInternals>>;
+        terms?: Record<string, ExtensionTerm>;
+        validate?(value: any, helpers: CustomHelpers): any;
+
+        /**
+         * undocumented options
+         */
+        cast?: Record<string, { from(value: any): any; to(value: any, helpers: CustomHelpers): any }>;
+        properties?: Record<string, any>;
+    }
+
+    type ExtensionFactory = (joi: Root) => Extension;
+
+    interface Err {
+        toString(): string;
+    }
+
+    // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
+
+    interface Root {
+        /**
+         * Current version of the joi package.
+         */
+        version: string;
+
+        ValidationError: new (message: string, details: any, original: any) => ValidationError;
+
+        /**
+         * Generates a schema object that matches any data type.
+         */
+        any(): AnySchema;
+
+        /**
+         * Generates a schema object that matches an array data type.
+         */
+        array(): ArraySchema;
+
+        /**
+         * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool().
+         */
+        bool(): BooleanSchema;
+
+        /**
+         * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool().
+         */
+        boolean(): BooleanSchema;
+
+        /**
+         * Generates a schema object that matches a Buffer data type (as well as the strings which will be converted to Buffers).
+         */
+        binary(): BinarySchema;
+
+        /**
+         * Generates a schema object that matches a date type (as well as a JavaScript date string or number of milliseconds).
+         */
+        date(): DateSchema;
+
+        /**
+         * Generates a schema object that matches a function type.
+         */
+        func(): FunctionSchema;
+
+        /**
+         * Generates a schema object that matches a function type.
+         */
+        function(): FunctionSchema;
+
+        /**
+         * Generates a schema object that matches a number data type (as well as strings that can be converted to numbers).
+         */
+        number(): NumberSchema;
+
+        /**
+         * Generates a schema object that matches an object data type (as well as JSON strings that have been parsed into objects).
+         */
+        // tslint:disable-next-line:no-unnecessary-generics
+        object<TSchema = any, T = TSchema>(schema?: SchemaMap<T>): ObjectSchema<TSchema>;
+
+        /**
+         * Generates a schema object that matches a string data type. Note that empty strings are not allowed by default and must be enabled with allow('').
+         */
+        string(): StringSchema;
+
+        /**
+         * Generates a schema object that matches any symbol.
+         */
+        symbol(): SymbolSchema;
+
+        /**
+         * Generates a type that will match one of the provided alternative schemas
+         */
+        alternatives(types: SchemaLike[]): AlternativesSchema;
+        alternatives(...types: SchemaLike[]): AlternativesSchema;
+
+        /**
+         * Alias for `alternatives`
+         */
+        alt(types: SchemaLike[]): AlternativesSchema;
+        alt(...types: SchemaLike[]): AlternativesSchema;
+
+        /**
+         * Links to another schema node and reuses it for validation, typically for creative recursive schemas.
+         *
+         * @param ref - the reference to the linked schema node.
+         * Cannot reference itself or its children as well as other links.
+         * Links can be expressed in relative terms like value references (`Joi.link('...')`),
+         * in absolute terms from the schema run-time root (`Joi.link('/a')`),
+         * or using schema ids implicitly using object keys or explicitly using `any.id()` (`Joi.link('#a.b.c')`).
+         */
+        link(ref?: string): LinkSchema;
+
+        /**
+         * Validates a value against a schema and throws if validation fails.
+         *
+         * @param value - the value to validate.
+         * @param schema - the schema object.
+         * @param message - optional message string prefix added in front of the error message. may also be an Error object.
+         */
+        assert(value: any, schema: Schema, options?: ValidationOptions): void;
+        assert(value: any, schema: Schema, message: string | Error, options?: ValidationOptions): void;
+
+        /**
+         * Validates a value against a schema, returns valid object, and throws if validation fails.
+         *
+         * @param value - the value to validate.
+         * @param schema - the schema object.
+         * @param message - optional message string prefix added in front of the error message. may also be an Error object.
+         */
+        attempt(value: any, schema: Schema, options?: ValidationOptions): any;
+        attempt(value: any, schema: Schema, message: string | Error, options?: ValidationOptions): any;
+
+        cache: CacheConfiguration;
+
+        /**
+         * Converts literal schema definition to joi schema object (or returns the same back if already a joi schema object).
+         */
+        compile(schema: SchemaLike, options?: CompileOptions): Schema;
+
+        /**
+         * Checks if the provided preferences are valid.
+         *
+         * Throws an exception if the prefs object is invalid.
+         *
+         * The method is provided to perform inputs validation for the `any.validate()` and `any.validateAsync()` methods.
+         * Validation is not performed automatically for performance reasons. Instead, manually validate the preferences passed once and reuse.
+         */
+        checkPreferences(prefs: ValidationOptions): void;
+
+        /**
+         * Creates a custom validation schema.
+         */
+        custom(fn: CustomValidator, description?: string): Schema;
+
+        /**
+         * Creates a new Joi instance that will apply defaults onto newly created schemas
+         * through the use of the fn function that takes exactly one argument, the schema being created.
+         *
+         * @param fn - The function must always return a schema, even if untransformed.
+         */
+        defaults(fn: SchemaFunction): Root;
+
+        /**
+         * Generates a dynamic expression using a template string.
+         */
+        expression(template: string, options?: ReferenceOptions): any;
+
+        /**
+         * Creates a new Joi instance customized with the extension(s) you provide included.
+         */
+        extend(...extensions: Array<Extension | ExtensionFactory>): any;
+
+        /**
+         * Creates a reference that when resolved, is used as an array of values to match against the rule.
+         */
+        in(ref: string, options?: ReferenceOptions): Reference;
+
+        /**
+         * Checks whether or not the provided argument is an instance of ValidationError
+         */
+        isError(error: any): error is ValidationError;
+
+        /**
+         * Checks whether or not the provided argument is an expression.
+         */
+        isExpression(expression: any): boolean;
+
+        /**
+         * Checks whether or not the provided argument is a reference. It's especially useful if you want to post-process error messages.
+         */
+        isRef(ref: any): ref is Reference;
+
+        /**
+         * Checks whether or not the provided argument is a joi schema.
+         */
+        isSchema(schema: any, options?: CompileOptions): boolean;
+
+        /**
+         * A special value used with `any.allow()`, `any.invalid()`, and `any.valid()` as the first value to reset any previously set values.
+         */
+        override: symbol;
+
+        /**
+         * Generates a reference to the value of the named key.
+         */
+        ref(key: string, options?: ReferenceOptions): Reference;
+
+        /**
+         * Returns an object where each key is a plain joi schema type.
+         * Useful for creating type shortcuts using deconstruction.
+         * Note that the types are already formed and do not need to be called as functions (e.g. `string`, not `string()`).
+         */
+        types(): {
+            alternatives: AlternativesSchema;
+            any: AnySchema;
+            array: ArraySchema;
+            binary: BinarySchema;
+            boolean: BooleanSchema;
+            date: DateSchema;
+            function: FunctionSchema;
+            link: LinkSchema;
+            number: NumberSchema;
+            object: ObjectSchema;
+            string: StringSchema;
+            symbol: SymbolSchema;
+        };
+
+        /**
+         * Generates a dynamic expression using a template string.
+         */
+        x(template: string, options?: ReferenceOptions): any;
+
+        // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
+        // Below are undocumented APIs. use at your own risk
+        // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
+
+        /**
+         * Whitelists a value
+         */
+        allow(...values: any[]): Schema;
+
+        /**
+         * Adds the provided values into the allowed whitelist and marks them as the only valid values allowed.
+         */
+        valid(...values: any[]): Schema;
+        equal(...values: any[]): Schema;
+
+        /**
+         * Blacklists a value
+         */
+        invalid(...values: any[]): Schema;
+        disallow(...values: any[]): Schema;
+        not(...values: any[]): Schema;
+
+        /**
+         * Marks a key as required which will not allow undefined as value. All keys are optional by default.
+         */
+        required(): Schema;
+
+        /**
+         * Alias of `required`.
+         */
+        exist(): Schema;
+
+        /**
+         * Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default.
+         */
+        optional(): Schema;
+
+        /**
+         * Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys.
+         */
+        forbidden(): Schema;
+
+        /**
+         * Overrides the global validate() options for the current key and any sub-key.
+         */
+        preferences(options: ValidationOptions): Schema;
+
+        /**
+         * Overrides the global validate() options for the current key and any sub-key.
+         */
+        prefs(options: ValidationOptions): Schema;
+
+        /**
+         * Converts the type into an alternatives type where the conditions are merged into the type definition where:
+         */
+        when(ref: string | Reference, options: WhenOptions): AlternativesSchema;
+        when(ref: Schema, options: WhenSchemaOptions): AlternativesSchema;
+
+        /**
+         * Unsure, maybe alias for `compile`?
+         */
+        build(...args: any[]): any;
+
+        /**
+         * Unsure, maybe alias for `preferences`?
+         */
+        options(...args: any[]): any;
+
+        /**
+         * Unsure, maybe leaked from `@hapi/lab/coverage/initialize`
+         */
+        trace(...args: any[]): any;
+        untrace(...args: any[]): any;
+    }
+}
+
+declare const Joi: Joi.Root;
+export = Joi;
diff --git a/node_modules/joi/lib/index.js b/node_modules/joi/lib/index.js
new file mode 100644
index 00000000..8813f516
--- /dev/null
+++ b/node_modules/joi/lib/index.js
@@ -0,0 +1,283 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+
+const Cache = require('./cache');
+const Common = require('./common');
+const Compile = require('./compile');
+const Errors = require('./errors');
+const Extend = require('./extend');
+const Manifest = require('./manifest');
+const Ref = require('./ref');
+const Template = require('./template');
+const Trace = require('./trace');
+
+let Schemas;
+
+
+const internals = {
+    types: {
+        alternatives: require('./types/alternatives'),
+        any: require('./types/any'),
+        array: require('./types/array'),
+        boolean: require('./types/boolean'),
+        date: require('./types/date'),
+        function: require('./types/function'),
+        link: require('./types/link'),
+        number: require('./types/number'),
+        object: require('./types/object'),
+        string: require('./types/string'),
+        symbol: require('./types/symbol')
+    },
+    aliases: {
+        alt: 'alternatives',
+        bool: 'boolean',
+        func: 'function'
+    }
+};
+
+
+if (Buffer) {                                                           // $lab:coverage:ignore$
+    internals.types.binary = require('./types/binary');
+}
+
+
+internals.root = function () {
+
+    const root = {
+        _types: new Set(Object.keys(internals.types))
+    };
+
+    // Types
+
+    for (const type of root._types) {
+        root[type] = function (...args) {
+
+            Assert(!args.length || ['alternatives', 'link', 'object'].includes(type), 'The', type, 'type does not allow arguments');
+            return internals.generate(this, internals.types[type], args);
+        };
+    }
+
+    // Shortcuts
+
+    for (const method of ['allow', 'custom', 'disallow', 'equal', 'exist', 'forbidden', 'invalid', 'not', 'only', 'optional', 'options', 'prefs', 'preferences', 'required', 'strip', 'valid', 'when']) {
+        root[method] = function (...args) {
+
+            return this.any()[method](...args);
+        };
+    }
+
+    // Methods
+
+    Object.assign(root, internals.methods);
+
+    // Aliases
+
+    for (const alias in internals.aliases) {
+        const target = internals.aliases[alias];
+        root[alias] = root[target];
+    }
+
+    root.x = root.expression;
+
+    // Trace
+
+    if (Trace.setup) {                                          // $lab:coverage:ignore$
+        Trace.setup(root);
+    }
+
+    return root;
+};
+
+
+internals.methods = {
+
+    ValidationError: Errors.ValidationError,
+    version: Common.version,
+    cache: Cache.provider,
+
+    assert(value, schema, ...args /* [message], [options] */) {
+
+        internals.assert(value, schema, true, args);
+    },
+
+    attempt(value, schema, ...args /* [message], [options] */) {
+
+        return internals.assert(value, schema, false, args);
+    },
+
+    build(desc) {
+
+        Assert(typeof Manifest.build === 'function', 'Manifest functionality disabled');
+        return Manifest.build(this, desc);
+    },
+
+    checkPreferences(prefs) {
+
+        Common.checkPreferences(prefs);
+    },
+
+    compile(schema, options) {
+
+        return Compile.compile(this, schema, options);
+    },
+
+    defaults(modifier) {
+
+        Assert(typeof modifier === 'function', 'modifier must be a function');
+
+        const joi = Object.assign({}, this);
+        for (const type of joi._types) {
+            const schema = modifier(joi[type]());
+            Assert(Common.isSchema(schema), 'modifier must return a valid schema object');
+
+            joi[type] = function (...args) {
+
+                return internals.generate(this, schema, args);
+            };
+        }
+
+        return joi;
+    },
+
+    expression(...args) {
+
+        return new Template(...args);
+    },
+
+    extend(...extensions) {
+
+        Common.verifyFlat(extensions, 'extend');
+
+        Schemas = Schemas || require('./schemas');
+
+        Assert(extensions.length, 'You need to provide at least one extension');
+        this.assert(extensions, Schemas.extensions);
+
+        const joi = Object.assign({}, this);
+        joi._types = new Set(joi._types);
+
+        for (let extension of extensions) {
+            if (typeof extension === 'function') {
+                extension = extension(joi);
+            }
+
+            this.assert(extension, Schemas.extension);
+
+            const expanded = internals.expandExtension(extension, joi);
+            for (const item of expanded) {
+                Assert(joi[item.type] === undefined || joi._types.has(item.type), 'Cannot override name', item.type);
+
+                const base = item.base || this.any();
+                const schema = Extend.type(base, item);
+
+                joi._types.add(item.type);
+                joi[item.type] = function (...args) {
+
+                    return internals.generate(this, schema, args);
+                };
+            }
+        }
+
+        return joi;
+    },
+
+    isError: Errors.ValidationError.isError,
+    isExpression: Template.isTemplate,
+    isRef: Ref.isRef,
+    isSchema: Common.isSchema,
+
+    in(...args) {
+
+        return Ref.in(...args);
+    },
+
+    override: Common.symbols.override,
+
+    ref(...args) {
+
+        return Ref.create(...args);
+    },
+
+    types() {
+
+        const types = {};
+        for (const type of this._types) {
+            types[type] = this[type]();
+        }
+
+        for (const target in internals.aliases) {
+            types[target] = this[target]();
+        }
+
+        return types;
+    }
+};
+
+
+// Helpers
+
+internals.assert = function (value, schema, annotate, args /* [message], [options] */) {
+
+    const message = args[0] instanceof Error || typeof args[0] === 'string' ? args[0] : null;
+    const options = message ? args[1] : args[0];
+    const result = schema.validate(value, Common.preferences({ errors: { stack: true } }, options || {}));
+
+    let error = result.error;
+    if (!error) {
+        return result.value;
+    }
+
+    if (message instanceof Error) {
+        throw message;
+    }
+
+    const display = annotate && typeof error.annotate === 'function' ? error.annotate() : error.message;
+
+    if (error instanceof Errors.ValidationError === false) {
+        error = Clone(error);
+    }
+
+    error.message = message ? `${message} ${display}` : display;
+    throw error;
+};
+
+
+internals.generate = function (root, schema, args) {
+
+    Assert(root, 'Must be invoked on a Joi instance.');
+
+    schema.$_root = root;
+
+    if (!schema._definition.args ||
+        !args.length) {
+
+        return schema;
+    }
+
+    return schema._definition.args(schema, ...args);
+};
+
+
+internals.expandExtension = function (extension, joi) {
+
+    if (typeof extension.type === 'string') {
+        return [extension];
+    }
+
+    const extended = [];
+    for (const type of joi._types) {
+        if (extension.type.test(type)) {
+            const item = Object.assign({}, extension);
+            item.type = type;
+            item.base = joi[type]();
+            extended.push(item);
+        }
+    }
+
+    return extended;
+};
+
+
+module.exports = internals.root();
diff --git a/node_modules/joi/lib/manifest.js b/node_modules/joi/lib/manifest.js
new file mode 100644
index 00000000..8fed3c92
--- /dev/null
+++ b/node_modules/joi/lib/manifest.js
@@ -0,0 +1,476 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+
+const Common = require('./common');
+const Messages = require('./messages');
+const Ref = require('./ref');
+const Template = require('./template');
+
+let Schemas;
+
+
+const internals = {};
+
+
+exports.describe = function (schema) {
+
+    const def = schema._definition;
+
+    // Type
+
+    const desc = {
+        type: schema.type,
+        flags: {},
+        rules: []
+    };
+
+    // Flags
+
+    for (const flag in schema._flags) {
+        if (flag[0] !== '_') {
+            desc.flags[flag] = internals.describe(schema._flags[flag]);
+        }
+    }
+
+    if (!Object.keys(desc.flags).length) {
+        delete desc.flags;
+    }
+
+    // Preferences
+
+    if (schema._preferences) {
+        desc.preferences = Clone(schema._preferences, { shallow: ['messages'] });
+        delete desc.preferences[Common.symbols.prefs];
+        if (desc.preferences.messages) {
+            desc.preferences.messages = Messages.decompile(desc.preferences.messages);
+        }
+    }
+
+    // Allow / Invalid
+
+    if (schema._valids) {
+        desc.allow = schema._valids.describe();
+    }
+
+    if (schema._invalids) {
+        desc.invalid = schema._invalids.describe();
+    }
+
+    // Rules
+
+    for (const rule of schema._rules) {
+        const ruleDef = def.rules[rule.name];
+        if (ruleDef.manifest === false) {                           // Defaults to true
+            continue;
+        }
+
+        const item = { name: rule.name };
+
+        for (const custom in def.modifiers) {
+            if (rule[custom] !== undefined) {
+                item[custom] = internals.describe(rule[custom]);
+            }
+        }
+
+        if (rule.args) {
+            item.args = {};
+            for (const key in rule.args) {
+                const arg = rule.args[key];
+                if (key === 'options' &&
+                    !Object.keys(arg).length) {
+
+                    continue;
+                }
+
+                item.args[key] = internals.describe(arg, { assign: key });
+            }
+
+            if (!Object.keys(item.args).length) {
+                delete item.args;
+            }
+        }
+
+        desc.rules.push(item);
+    }
+
+    if (!desc.rules.length) {
+        delete desc.rules;
+    }
+
+    // Terms (must be last to verify no name conflicts)
+
+    for (const term in schema.$_terms) {
+        if (term[0] === '_') {
+            continue;
+        }
+
+        Assert(!desc[term], 'Cannot describe schema due to internal name conflict with', term);
+
+        const items = schema.$_terms[term];
+        if (!items) {
+            continue;
+        }
+
+        if (items instanceof Map) {
+            if (items.size) {
+                desc[term] = [...items.entries()];
+            }
+
+            continue;
+        }
+
+        if (Common.isValues(items)) {
+            desc[term] = items.describe();
+            continue;
+        }
+
+        Assert(def.terms[term], 'Term', term, 'missing configuration');
+        const manifest = def.terms[term].manifest;
+        const mapped = typeof manifest === 'object';
+        if (!items.length &&
+            !mapped) {
+
+            continue;
+        }
+
+        const normalized = [];
+        for (const item of items) {
+            normalized.push(internals.describe(item));
+        }
+
+        // Mapped
+
+        if (mapped) {
+            const { from, to } = manifest.mapped;
+            desc[term] = {};
+            for (const item of normalized) {
+                desc[term][item[to]] = item[from];
+            }
+
+            continue;
+        }
+
+        // Single
+
+        if (manifest === 'single') {
+            Assert(normalized.length === 1, 'Term', term, 'contains more than one item');
+            desc[term] = normalized[0];
+            continue;
+        }
+
+        // Array
+
+        desc[term] = normalized;
+    }
+
+    internals.validate(schema.$_root, desc);
+    return desc;
+};
+
+
+internals.describe = function (item, options = {}) {
+
+    if (Array.isArray(item)) {
+        return item.map(internals.describe);
+    }
+
+    if (item === Common.symbols.deepDefault) {
+        return { special: 'deep' };
+    }
+
+    if (typeof item !== 'object' ||
+        item === null) {
+
+        return item;
+    }
+
+    if (options.assign === 'options') {
+        return Clone(item);
+    }
+
+    if (Buffer && Buffer.isBuffer(item)) {                          // $lab:coverage:ignore$
+        return { buffer: item.toString('binary') };
+    }
+
+    if (item instanceof Date) {
+        return item.toISOString();
+    }
+
+    if (item instanceof Error) {
+        return item;
+    }
+
+    if (item instanceof RegExp) {
+        if (options.assign === 'regex') {
+            return item.toString();
+        }
+
+        return { regex: item.toString() };
+    }
+
+    if (item[Common.symbols.literal]) {
+        return { function: item.literal };
+    }
+
+    if (typeof item.describe === 'function') {
+        if (options.assign === 'ref') {
+            return item.describe().ref;
+        }
+
+        return item.describe();
+    }
+
+    const normalized = {};
+    for (const key in item) {
+        const value = item[key];
+        if (value === undefined) {
+            continue;
+        }
+
+        normalized[key] = internals.describe(value, { assign: key });
+    }
+
+    return normalized;
+};
+
+
+exports.build = function (joi, desc) {
+
+    const builder = new internals.Builder(joi);
+    return builder.parse(desc);
+};
+
+
+internals.Builder = class {
+
+    constructor(joi) {
+
+        this.joi = joi;
+    }
+
+    parse(desc) {
+
+        internals.validate(this.joi, desc);
+
+        // Type
+
+        let schema = this.joi[desc.type]()._bare();
+        const def = schema._definition;
+
+        // Flags
+
+        if (desc.flags) {
+            for (const flag in desc.flags) {
+                const setter = def.flags[flag] && def.flags[flag].setter || flag;
+                Assert(typeof schema[setter] === 'function', 'Invalid flag', flag, 'for type', desc.type);
+                schema = schema[setter](this.build(desc.flags[flag]));
+            }
+        }
+
+        // Preferences
+
+        if (desc.preferences) {
+            schema = schema.preferences(this.build(desc.preferences));
+        }
+
+        // Allow / Invalid
+
+        if (desc.allow) {
+            schema = schema.allow(...this.build(desc.allow));
+        }
+
+        if (desc.invalid) {
+            schema = schema.invalid(...this.build(desc.invalid));
+        }
+
+        // Rules
+
+        if (desc.rules) {
+            for (const rule of desc.rules) {
+                Assert(typeof schema[rule.name] === 'function', 'Invalid rule', rule.name, 'for type', desc.type);
+
+                const args = [];
+                if (rule.args) {
+                    const built = {};
+                    for (const key in rule.args) {
+                        built[key] = this.build(rule.args[key], { assign: key });
+                    }
+
+                    const keys = Object.keys(built);
+                    const definition = def.rules[rule.name].args;
+                    if (definition) {
+                        Assert(keys.length <= definition.length, 'Invalid number of arguments for', desc.type, rule.name, '(expected up to', definition.length, ', found', keys.length, ')');
+                        for (const { name } of definition) {
+                            args.push(built[name]);
+                        }
+                    }
+                    else {
+                        Assert(keys.length === 1, 'Invalid number of arguments for', desc.type, rule.name, '(expected up to 1, found', keys.length, ')');
+                        args.push(built[keys[0]]);
+                    }
+                }
+
+                // Apply
+
+                schema = schema[rule.name](...args);
+
+                // Ruleset
+
+                const options = {};
+                for (const custom in def.modifiers) {
+                    if (rule[custom] !== undefined) {
+                        options[custom] = this.build(rule[custom]);
+                    }
+                }
+
+                if (Object.keys(options).length) {
+                    schema = schema.rule(options);
+                }
+            }
+        }
+
+        // Terms
+
+        const terms = {};
+        for (const key in desc) {
+            if (['allow', 'flags', 'invalid', 'whens', 'preferences', 'rules', 'type'].includes(key)) {
+                continue;
+            }
+
+            Assert(def.terms[key], 'Term', key, 'missing configuration');
+            const manifest = def.terms[key].manifest;
+
+            if (manifest === 'schema') {
+                terms[key] = desc[key].map((item) => this.parse(item));
+                continue;
+            }
+
+            if (manifest === 'values') {
+                terms[key] = desc[key].map((item) => this.build(item));
+                continue;
+            }
+
+            if (manifest === 'single') {
+                terms[key] = this.build(desc[key]);
+                continue;
+            }
+
+            if (typeof manifest === 'object') {
+                terms[key] = {};
+                for (const name in desc[key]) {
+                    const value = desc[key][name];
+                    terms[key][name] = this.parse(value);
+                }
+
+                continue;
+            }
+
+            terms[key] = this.build(desc[key]);
+        }
+
+        if (desc.whens) {
+            terms.whens = desc.whens.map((when) => this.build(when));
+        }
+
+        schema = def.manifest.build(schema, terms);
+        schema.$_temp.ruleset = false;
+        return schema;
+    }
+
+    build(desc, options = {}) {
+
+        if (desc === null) {
+            return null;
+        }
+
+        if (Array.isArray(desc)) {
+            return desc.map((item) => this.build(item));
+        }
+
+        if (desc instanceof Error) {
+            return desc;
+        }
+
+        if (options.assign === 'options') {
+            return Clone(desc);
+        }
+
+        if (options.assign === 'regex') {
+            return internals.regex(desc);
+        }
+
+        if (options.assign === 'ref') {
+            return Ref.build(desc);
+        }
+
+        if (typeof desc !== 'object') {
+            return desc;
+        }
+
+        if (Object.keys(desc).length === 1) {
+            if (desc.buffer) {
+                Assert(Buffer, 'Buffers are not supported');
+                return Buffer && Buffer.from(desc.buffer, 'binary');                    // $lab:coverage:ignore$
+            }
+
+            if (desc.function) {
+                return { [Common.symbols.literal]: true, literal: desc.function };
+            }
+
+            if (desc.override) {
+                return Common.symbols.override;
+            }
+
+            if (desc.ref) {
+                return Ref.build(desc.ref);
+            }
+
+            if (desc.regex) {
+                return internals.regex(desc.regex);
+            }
+
+            if (desc.special) {
+                Assert(['deep'].includes(desc.special), 'Unknown special value', desc.special);
+                return Common.symbols.deepDefault;
+            }
+
+            if (desc.value) {
+                return Clone(desc.value);
+            }
+        }
+
+        if (desc.type) {
+            return this.parse(desc);
+        }
+
+        if (desc.template) {
+            return Template.build(desc);
+        }
+
+        const normalized = {};
+        for (const key in desc) {
+            normalized[key] = this.build(desc[key], { assign: key });
+        }
+
+        return normalized;
+    }
+};
+
+
+internals.regex = function (string) {
+
+    const end = string.lastIndexOf('/');
+    const exp = string.slice(1, end);
+    const flags = string.slice(end + 1);
+    return new RegExp(exp, flags);
+};
+
+
+internals.validate = function (joi, desc) {
+
+    Schemas = Schemas || require('./schemas');
+
+    joi.assert(desc, Schemas.description);
+};
diff --git a/node_modules/joi/lib/messages.js b/node_modules/joi/lib/messages.js
new file mode 100644
index 00000000..f719779b
--- /dev/null
+++ b/node_modules/joi/lib/messages.js
@@ -0,0 +1,178 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+
+const Template = require('./template');
+
+
+const internals = {};
+
+
+exports.compile = function (messages, target) {
+
+    // Single value string ('plain error message', 'template {error} message')
+
+    if (typeof messages === 'string') {
+        Assert(!target, 'Cannot set single message string');
+        return new Template(messages);
+    }
+
+    // Single value template
+
+    if (Template.isTemplate(messages)) {
+        Assert(!target, 'Cannot set single message template');
+        return messages;
+    }
+
+    // By error code { 'number.min': <string | template> }
+
+    Assert(typeof messages === 'object' && !Array.isArray(messages), 'Invalid message options');
+
+    target = target ? Clone(target) : {};
+
+    for (let code in messages) {
+        const message = messages[code];
+
+        if (code === 'root' ||
+            Template.isTemplate(message)) {
+
+            target[code] = message;
+            continue;
+        }
+
+        if (typeof message === 'string') {
+            target[code] = new Template(message);
+            continue;
+        }
+
+        // By language { english: { 'number.min': <string | template> } }
+
+        Assert(typeof message === 'object' && !Array.isArray(message), 'Invalid message for', code);
+
+        const language = code;
+        target[language] = target[language] || {};
+
+        for (code in message) {
+            const localized = message[code];
+
+            if (code === 'root' ||
+                Template.isTemplate(localized)) {
+
+                target[language][code] = localized;
+                continue;
+            }
+
+            Assert(typeof localized === 'string', 'Invalid message for', code, 'in', language);
+            target[language][code] = new Template(localized);
+        }
+    }
+
+    return target;
+};
+
+
+exports.decompile = function (messages) {
+
+    // By error code { 'number.min': <string | template> }
+
+    const target = {};
+    for (let code in messages) {
+        const message = messages[code];
+
+        if (code === 'root') {
+            target[code] = message;
+            continue;
+        }
+
+        if (Template.isTemplate(message)) {
+            target[code] = message.describe({ compact: true });
+            continue;
+        }
+
+        // By language { english: { 'number.min': <string | template> } }
+
+        const language = code;
+        target[language] = {};
+
+        for (code in message) {
+            const localized = message[code];
+
+            if (code === 'root') {
+                target[language][code] = localized;
+                continue;
+            }
+
+            target[language][code] = localized.describe({ compact: true });
+        }
+    }
+
+    return target;
+};
+
+
+exports.merge = function (base, extended) {
+
+    if (!base) {
+        return exports.compile(extended);
+    }
+
+    if (!extended) {
+        return base;
+    }
+
+    // Single value string
+
+    if (typeof extended === 'string') {
+        return new Template(extended);
+    }
+
+    // Single value template
+
+    if (Template.isTemplate(extended)) {
+        return extended;
+    }
+
+    // By error code { 'number.min': <string | template> }
+
+    const target = Clone(base);
+
+    for (let code in extended) {
+        const message = extended[code];
+
+        if (code === 'root' ||
+            Template.isTemplate(message)) {
+
+            target[code] = message;
+            continue;
+        }
+
+        if (typeof message === 'string') {
+            target[code] = new Template(message);
+            continue;
+        }
+
+        // By language { english: { 'number.min': <string | template> } }
+
+        Assert(typeof message === 'object' && !Array.isArray(message), 'Invalid message for', code);
+
+        const language = code;
+        target[language] = target[language] || {};
+
+        for (code in message) {
+            const localized = message[code];
+
+            if (code === 'root' ||
+                Template.isTemplate(localized)) {
+
+                target[language][code] = localized;
+                continue;
+            }
+
+            Assert(typeof localized === 'string', 'Invalid message for', code, 'in', language);
+            target[language][code] = new Template(localized);
+        }
+    }
+
+    return target;
+};
diff --git a/node_modules/joi/lib/modify.js b/node_modules/joi/lib/modify.js
new file mode 100644
index 00000000..6f148484
--- /dev/null
+++ b/node_modules/joi/lib/modify.js
@@ -0,0 +1,267 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Common = require('./common');
+const Ref = require('./ref');
+
+
+const internals = {};
+
+
+
+exports.Ids = internals.Ids = class {
+
+    constructor() {
+
+        this._byId = new Map();
+        this._byKey = new Map();
+        this._schemaChain = false;
+    }
+
+    clone() {
+
+        const clone = new internals.Ids();
+        clone._byId = new Map(this._byId);
+        clone._byKey = new Map(this._byKey);
+        clone._schemaChain = this._schemaChain;
+        return clone;
+    }
+
+    concat(source) {
+
+        if (source._schemaChain) {
+            this._schemaChain = true;
+        }
+
+        for (const [id, value] of source._byId.entries()) {
+            Assert(!this._byKey.has(id), 'Schema id conflicts with existing key:', id);
+            this._byId.set(id, value);
+        }
+
+        for (const [key, value] of source._byKey.entries()) {
+            Assert(!this._byId.has(key), 'Schema key conflicts with existing id:', key);
+            this._byKey.set(key, value);
+        }
+    }
+
+    fork(path, adjuster, root) {
+
+        const chain = this._collect(path);
+        chain.push({ schema: root });
+        const tail = chain.shift();
+        let adjusted = { id: tail.id, schema: adjuster(tail.schema) };
+
+        Assert(Common.isSchema(adjusted.schema), 'adjuster function failed to return a joi schema type');
+
+        for (const node of chain) {
+            adjusted = { id: node.id, schema: internals.fork(node.schema, adjusted.id, adjusted.schema) };
+        }
+
+        return adjusted.schema;
+    }
+
+    labels(path, behind = []) {
+
+        const current = path[0];
+        const node = this._get(current);
+        if (!node) {
+            return [...behind, ...path].join('.');
+        }
+
+        const forward = path.slice(1);
+        behind = [...behind, node.schema._flags.label || current];
+        if (!forward.length) {
+            return behind.join('.');
+        }
+
+        return node.schema._ids.labels(forward, behind);
+    }
+
+    reach(path, behind = []) {
+
+        const current = path[0];
+        const node = this._get(current);
+        Assert(node, 'Schema does not contain path', [...behind, ...path].join('.'));
+
+        const forward = path.slice(1);
+        if (!forward.length) {
+            return node.schema;
+        }
+
+        return node.schema._ids.reach(forward, [...behind, current]);
+    }
+
+    register(schema, { key } = {}) {
+
+        if (!schema ||
+            !Common.isSchema(schema)) {
+
+            return;
+        }
+
+        if (schema.$_property('schemaChain') ||
+            schema._ids._schemaChain) {
+
+            this._schemaChain = true;
+        }
+
+        const id = schema._flags.id;
+        if (id) {
+            const existing = this._byId.get(id);
+            Assert(!existing || existing.schema === schema, 'Cannot add different schemas with the same id:', id);
+            Assert(!this._byKey.has(id), 'Schema id conflicts with existing key:', id);
+
+            this._byId.set(id, { schema, id });
+        }
+
+        if (key) {
+            Assert(!this._byKey.has(key), 'Schema already contains key:', key);
+            Assert(!this._byId.has(key), 'Schema key conflicts with existing id:', key);
+
+            this._byKey.set(key, { schema, id: key });
+        }
+    }
+
+    reset() {
+
+        this._byId = new Map();
+        this._byKey = new Map();
+        this._schemaChain = false;
+    }
+
+    _collect(path, behind = [], nodes = []) {
+
+        const current = path[0];
+        const node = this._get(current);
+        Assert(node, 'Schema does not contain path', [...behind, ...path].join('.'));
+
+        nodes = [node, ...nodes];
+
+        const forward = path.slice(1);
+        if (!forward.length) {
+            return nodes;
+        }
+
+        return node.schema._ids._collect(forward, [...behind, current], nodes);
+    }
+
+    _get(id) {
+
+        return this._byId.get(id) || this._byKey.get(id);
+    }
+};
+
+
+internals.fork = function (schema, id, replacement) {
+
+    const each = (item, { key }) => {
+
+        if (id === (item._flags.id || key)) {
+            return replacement;
+        }
+    };
+
+    const obj = exports.schema(schema, { each, ref: false });
+    return obj ? obj.$_mutateRebuild() : schema;
+};
+
+
+exports.schema = function (schema, options) {
+
+    let obj;
+
+    for (const name in schema._flags) {
+        if (name[0] === '_') {
+            continue;
+        }
+
+        const result = internals.scan(schema._flags[name], { source: 'flags', name }, options);
+        if (result !== undefined) {
+            obj = obj || schema.clone();
+            obj._flags[name] = result;
+        }
+    }
+
+    for (let i = 0; i < schema._rules.length; ++i) {
+        const rule = schema._rules[i];
+        const result = internals.scan(rule.args, { source: 'rules', name: rule.name }, options);
+        if (result !== undefined) {
+            obj = obj || schema.clone();
+            const clone = Object.assign({}, rule);
+            clone.args = result;
+            obj._rules[i] = clone;
+
+            const existingUnique = obj._singleRules.get(rule.name);
+            if (existingUnique === rule) {
+                obj._singleRules.set(rule.name, clone);
+            }
+        }
+    }
+
+    for (const name in schema.$_terms) {
+        if (name[0] === '_') {
+            continue;
+        }
+
+        const result = internals.scan(schema.$_terms[name], { source: 'terms', name }, options);
+        if (result !== undefined) {
+            obj = obj || schema.clone();
+            obj.$_terms[name] = result;
+        }
+    }
+
+    return obj;
+};
+
+
+internals.scan = function (item, source, options, _path, _key) {
+
+    const path = _path || [];
+
+    if (item === null ||
+        typeof item !== 'object') {
+
+        return;
+    }
+
+    let clone;
+
+    if (Array.isArray(item)) {
+        for (let i = 0; i < item.length; ++i) {
+            const key = source.source === 'terms' && source.name === 'keys' && item[i].key;
+            const result = internals.scan(item[i], source, options, [i, ...path], key);
+            if (result !== undefined) {
+                clone = clone || item.slice();
+                clone[i] = result;
+            }
+        }
+
+        return clone;
+    }
+
+    if (options.schema !== false && Common.isSchema(item) ||
+        options.ref !== false && Ref.isRef(item)) {
+
+        const result = options.each(item, { ...source, path, key: _key });
+        if (result === item) {
+            return;
+        }
+
+        return result;
+    }
+
+    for (const key in item) {
+        if (key[0] === '_') {
+            continue;
+        }
+
+        const result = internals.scan(item[key], source, options, [key, ...path], _key);
+        if (result !== undefined) {
+            clone = clone || Object.assign({}, item);
+            clone[key] = result;
+        }
+    }
+
+    return clone;
+};
diff --git a/node_modules/joi/lib/ref.js b/node_modules/joi/lib/ref.js
new file mode 100644
index 00000000..9f84a7b6
--- /dev/null
+++ b/node_modules/joi/lib/ref.js
@@ -0,0 +1,414 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+const Reach = require('@hapi/hoek/lib/reach');
+
+const Common = require('./common');
+
+let Template;
+
+
+const internals = {
+    symbol: Symbol('ref'),      // Used to internally identify references (shared with other joi versions)
+    defaults: {
+        adjust: null,
+        in: false,
+        iterables: null,
+        map: null,
+        separator: '.',
+        type: 'value'
+    }
+};
+
+
+exports.create = function (key, options = {}) {
+
+    Assert(typeof key === 'string', 'Invalid reference key:', key);
+    Common.assertOptions(options, ['adjust', 'ancestor', 'in', 'iterables', 'map', 'prefix', 'render', 'separator']);
+    Assert(!options.prefix || typeof options.prefix === 'object', 'options.prefix must be of type object');
+
+    const ref = Object.assign({}, internals.defaults, options);
+    delete ref.prefix;
+
+    const separator = ref.separator;
+    const context = internals.context(key, separator, options.prefix);
+    ref.type = context.type;
+    key = context.key;
+
+    if (ref.type === 'value') {
+        if (context.root) {
+            Assert(!separator || key[0] !== separator, 'Cannot specify relative path with root prefix');
+            ref.ancestor = 'root';
+            if (!key) {
+                key = null;
+            }
+        }
+
+        if (separator &&
+            separator === key) {
+
+            key = null;
+            ref.ancestor = 0;
+        }
+        else {
+            if (ref.ancestor !== undefined) {
+                Assert(!separator || !key || key[0] !== separator, 'Cannot combine prefix with ancestor option');
+            }
+            else {
+                const [ancestor, slice] = internals.ancestor(key, separator);
+                if (slice) {
+                    key = key.slice(slice);
+                    if (key === '') {
+                        key = null;
+                    }
+                }
+
+                ref.ancestor = ancestor;
+            }
+        }
+    }
+
+    ref.path = separator ? (key === null ? [] : key.split(separator)) : [key];
+
+    return new internals.Ref(ref);
+};
+
+
+exports.in = function (key, options = {}) {
+
+    return exports.create(key, { ...options, in: true });
+};
+
+
+exports.isRef = function (ref) {
+
+    return ref ? !!ref[Common.symbols.ref] : false;
+};
+
+
+internals.Ref = class {
+
+    constructor(options) {
+
+        Assert(typeof options === 'object', 'Invalid reference construction');
+        Common.assertOptions(options, [
+            'adjust', 'ancestor', 'in', 'iterables', 'map', 'path', 'render', 'separator', 'type',  // Copied
+            'depth', 'key', 'root', 'display'                                                       // Overridden
+        ]);
+
+        Assert([false, undefined].includes(options.separator) || typeof options.separator === 'string' && options.separator.length === 1, 'Invalid separator');
+        Assert(!options.adjust || typeof options.adjust === 'function', 'options.adjust must be a function');
+        Assert(!options.map || Array.isArray(options.map), 'options.map must be an array');
+        Assert(!options.map || !options.adjust, 'Cannot set both map and adjust options');
+
+        Object.assign(this, internals.defaults, options);
+
+        Assert(this.type === 'value' || this.ancestor === undefined, 'Non-value references cannot reference ancestors');
+
+        if (Array.isArray(this.map)) {
+            this.map = new Map(this.map);
+        }
+
+        this.depth = this.path.length;
+        this.key = this.path.length ? this.path.join(this.separator) : null;
+        this.root = this.path[0];
+
+        this.updateDisplay();
+    }
+
+    resolve(value, state, prefs, local, options = {}) {
+
+        Assert(!this.in || options.in, 'Invalid in() reference usage');
+
+        if (this.type === 'global') {
+            return this._resolve(prefs.context, state, options);
+        }
+
+        if (this.type === 'local') {
+            return this._resolve(local, state, options);
+        }
+
+        if (!this.ancestor) {
+            return this._resolve(value, state, options);
+        }
+
+        if (this.ancestor === 'root') {
+            return this._resolve(state.ancestors[state.ancestors.length - 1], state, options);
+        }
+
+        Assert(this.ancestor <= state.ancestors.length, 'Invalid reference exceeds the schema root:', this.display);
+        return this._resolve(state.ancestors[this.ancestor - 1], state, options);
+    }
+
+    _resolve(target, state, options) {
+
+        let resolved;
+
+        if (this.type === 'value' &&
+            state.mainstay.shadow &&
+            options.shadow !== false) {
+
+            resolved = state.mainstay.shadow.get(this.absolute(state));
+        }
+
+        if (resolved === undefined) {
+            resolved = Reach(target, this.path, { iterables: this.iterables, functions: true });
+        }
+
+        if (this.adjust) {
+            resolved = this.adjust(resolved);
+        }
+
+        if (this.map) {
+            const mapped = this.map.get(resolved);
+            if (mapped !== undefined) {
+                resolved = mapped;
+            }
+        }
+
+        if (state.mainstay) {
+            state.mainstay.tracer.resolve(state, this, resolved);
+        }
+
+        return resolved;
+    }
+
+    toString() {
+
+        return this.display;
+    }
+
+    absolute(state) {
+
+        return [...state.path.slice(0, -this.ancestor), ...this.path];
+    }
+
+    clone() {
+
+        return new internals.Ref(this);
+    }
+
+    describe() {
+
+        const ref = { path: this.path };
+
+        if (this.type !== 'value') {
+            ref.type = this.type;
+        }
+
+        if (this.separator !== '.') {
+            ref.separator = this.separator;
+        }
+
+        if (this.type === 'value' &&
+            this.ancestor !== 1) {
+
+            ref.ancestor = this.ancestor;
+        }
+
+        if (this.map) {
+            ref.map = [...this.map];
+        }
+
+        for (const key of ['adjust', 'iterables', 'render']) {
+            if (this[key] !== null &&
+                this[key] !== undefined) {
+
+                ref[key] = this[key];
+            }
+        }
+
+        if (this.in !== false) {
+            ref.in = true;
+        }
+
+        return { ref };
+    }
+
+    updateDisplay() {
+
+        const key = this.key !== null ? this.key : '';
+        if (this.type !== 'value') {
+            this.display = `ref:${this.type}:${key}`;
+            return;
+        }
+
+        if (!this.separator) {
+            this.display = `ref:${key}`;
+            return;
+        }
+
+        if (!this.ancestor) {
+            this.display = `ref:${this.separator}${key}`;
+            return;
+        }
+
+        if (this.ancestor === 'root') {
+            this.display = `ref:root:${key}`;
+            return;
+        }
+
+        if (this.ancestor === 1) {
+            this.display = `ref:${key || '..'}`;
+            return;
+        }
+
+        const lead = new Array(this.ancestor + 1).fill(this.separator).join('');
+        this.display = `ref:${lead}${key || ''}`;
+    }
+};
+
+
+internals.Ref.prototype[Common.symbols.ref] = true;
+
+
+exports.build = function (desc) {
+
+    desc = Object.assign({}, internals.defaults, desc);
+    if (desc.type === 'value' &&
+        desc.ancestor === undefined) {
+
+        desc.ancestor = 1;
+    }
+
+    return new internals.Ref(desc);
+};
+
+
+internals.context = function (key, separator, prefix = {}) {
+
+    key = key.trim();
+
+    if (prefix) {
+        const globalp = prefix.global === undefined ? '$' : prefix.global;
+        if (globalp !== separator &&
+            key.startsWith(globalp)) {
+
+            return { key: key.slice(globalp.length), type: 'global' };
+        }
+
+        const local = prefix.local === undefined ? '#' : prefix.local;
+        if (local !== separator &&
+            key.startsWith(local)) {
+
+            return { key: key.slice(local.length), type: 'local' };
+        }
+
+        const root = prefix.root === undefined ? '/' : prefix.root;
+        if (root !== separator &&
+            key.startsWith(root)) {
+
+            return { key: key.slice(root.length), type: 'value', root: true };
+        }
+    }
+
+    return { key, type: 'value' };
+};
+
+
+internals.ancestor = function (key, separator) {
+
+    if (!separator) {
+        return [1, 0];              // 'a_b' -> 1 (parent)
+    }
+
+    if (key[0] !== separator) {     // 'a.b' -> 1 (parent)
+        return [1, 0];
+    }
+
+    if (key[1] !== separator) {     // '.a.b' -> 0 (self)
+        return [0, 1];
+    }
+
+    let i = 2;
+    while (key[i] === separator) {
+        ++i;
+    }
+
+    return [i - 1, i];              // '...a.b.' -> 2 (grandparent)
+};
+
+
+exports.toSibling = 0;
+
+exports.toParent = 1;
+
+
+exports.Manager = class {
+
+    constructor() {
+
+        this.refs = [];                     // 0: [self refs], 1: [parent refs], 2: [grandparent refs], ...
+    }
+
+    register(source, target) {
+
+        if (!source) {
+            return;
+        }
+
+        target = target === undefined ? exports.toParent : target;
+
+        // Array
+
+        if (Array.isArray(source)) {
+            for (const ref of source) {
+                this.register(ref, target);
+            }
+
+            return;
+        }
+
+        // Schema
+
+        if (Common.isSchema(source)) {
+            for (const item of source._refs.refs) {
+                if (item.ancestor - target >= 0) {
+                    this.refs.push({ ancestor: item.ancestor - target, root: item.root });
+                }
+            }
+
+            return;
+        }
+
+        // Reference
+
+        if (exports.isRef(source) &&
+            source.type === 'value' &&
+            source.ancestor - target >= 0) {
+
+            this.refs.push({ ancestor: source.ancestor - target, root: source.root });
+        }
+
+        // Template
+
+        Template = Template || require('./template');
+
+        if (Template.isTemplate(source)) {
+            this.register(source.refs(), target);
+        }
+    }
+
+    get length() {
+
+        return this.refs.length;
+    }
+
+    clone() {
+
+        const copy = new exports.Manager();
+        copy.refs = Clone(this.refs);
+        return copy;
+    }
+
+    reset() {
+
+        this.refs = [];
+    }
+
+    roots() {
+
+        return this.refs.filter((ref) => !ref.ancestor).map((ref) => ref.root);
+    }
+};
diff --git a/node_modules/joi/lib/schemas.js b/node_modules/joi/lib/schemas.js
new file mode 100644
index 00000000..ab56109c
--- /dev/null
+++ b/node_modules/joi/lib/schemas.js
@@ -0,0 +1,301 @@
+'use strict';
+
+const Joi = require('./index');
+
+
+const internals = {};
+
+
+// Preferences
+
+internals.wrap = Joi.string()
+    .min(1)
+    .max(2)
+    .allow(false);
+
+
+exports.preferences = Joi.object({
+    allowUnknown: Joi.boolean(),
+    abortEarly: Joi.boolean(),
+    artifacts: Joi.boolean(),
+    cache: Joi.boolean(),
+    context: Joi.object(),
+    convert: Joi.boolean(),
+    dateFormat: Joi.valid('date', 'iso', 'string', 'time', 'utc'),
+    debug: Joi.boolean(),
+    errors: {
+        escapeHtml: Joi.boolean(),
+        label: Joi.valid('path', 'key', false),
+        language: [
+            Joi.string(),
+            Joi.object().ref()
+        ],
+        render: Joi.boolean(),
+        stack: Joi.boolean(),
+        wrap: {
+            label: internals.wrap,
+            array: internals.wrap
+        }
+    },
+    externals: Joi.boolean(),
+    messages: Joi.object(),
+    noDefaults: Joi.boolean(),
+    nonEnumerables: Joi.boolean(),
+    presence: Joi.valid('required', 'optional', 'forbidden'),
+    skipFunctions: Joi.boolean(),
+    stripUnknown: Joi.object({
+        arrays: Joi.boolean(),
+        objects: Joi.boolean()
+    })
+        .or('arrays', 'objects')
+        .allow(true, false),
+    warnings: Joi.boolean()
+})
+    .strict();
+
+
+// Extensions
+
+internals.nameRx = /^[a-zA-Z0-9]\w*$/;
+
+
+internals.rule = Joi.object({
+    alias: Joi.array().items(Joi.string().pattern(internals.nameRx)).single(),
+    args: Joi.array().items(
+        Joi.string(),
+        Joi.object({
+            name: Joi.string().pattern(internals.nameRx).required(),
+            ref: Joi.boolean(),
+            assert: Joi.alternatives([
+                Joi.function(),
+                Joi.object().schema()
+            ])
+                .conditional('ref', { is: true, then: Joi.required() }),
+            normalize: Joi.function(),
+            message: Joi.string().when('assert', { is: Joi.function(), then: Joi.required() })
+        })
+    ),
+    convert: Joi.boolean(),
+    manifest: Joi.boolean(),
+    method: Joi.function().allow(false),
+    multi: Joi.boolean(),
+    validate: Joi.function()
+});
+
+
+exports.extension = Joi.object({
+    type: Joi.alternatives([
+        Joi.string(),
+        Joi.object().regex()
+    ])
+        .required(),
+    args: Joi.function(),
+    cast: Joi.object().pattern(internals.nameRx, Joi.object({
+        from: Joi.function().maxArity(1).required(),
+        to: Joi.function().minArity(1).maxArity(2).required()
+    })),
+    base: Joi.object().schema()
+        .when('type', { is: Joi.object().regex(), then: Joi.forbidden() }),
+    coerce: [
+        Joi.function().maxArity(3),
+        Joi.object({ method: Joi.function().maxArity(3).required(), from: Joi.array().items(Joi.string()).single() })
+    ],
+    flags: Joi.object().pattern(internals.nameRx, Joi.object({
+        setter: Joi.string(),
+        default: Joi.any()
+    })),
+    manifest: {
+        build: Joi.function().arity(2)
+    },
+    messages: [Joi.object(), Joi.string()],
+    modifiers: Joi.object().pattern(internals.nameRx, Joi.function().minArity(1).maxArity(2)),
+    overrides: Joi.object().pattern(internals.nameRx, Joi.function()),
+    prepare: Joi.function().maxArity(3),
+    rebuild: Joi.function().arity(1),
+    rules: Joi.object().pattern(internals.nameRx, internals.rule),
+    terms: Joi.object().pattern(internals.nameRx, Joi.object({
+        init: Joi.array().allow(null).required(),
+        manifest: Joi.object().pattern(/.+/, [
+            Joi.valid('schema', 'single'),
+            Joi.object({
+                mapped: Joi.object({
+                    from: Joi.string().required(),
+                    to: Joi.string().required()
+                })
+                    .required()
+            })
+        ])
+    })),
+    validate: Joi.function().maxArity(3)
+})
+    .strict();
+
+
+exports.extensions = Joi.array().items(Joi.object(), Joi.function().arity(1)).strict();
+
+
+// Manifest
+
+internals.desc = {
+
+    buffer: Joi.object({
+        buffer: Joi.string()
+    }),
+
+    func: Joi.object({
+        function: Joi.function().required(),
+        options: {
+            literal: true
+        }
+    }),
+
+    override: Joi.object({
+        override: true
+    }),
+
+    ref: Joi.object({
+        ref: Joi.object({
+            type: Joi.valid('value', 'global', 'local'),
+            path: Joi.array().required(),
+            separator: Joi.string().length(1).allow(false),
+            ancestor: Joi.number().min(0).integer().allow('root'),
+            map: Joi.array().items(Joi.array().length(2)).min(1),
+            adjust: Joi.function(),
+            iterables: Joi.boolean(),
+            in: Joi.boolean(),
+            render: Joi.boolean()
+        })
+            .required()
+    }),
+
+    regex: Joi.object({
+        regex: Joi.string().min(3)
+    }),
+
+    special: Joi.object({
+        special: Joi.valid('deep').required()
+    }),
+
+    template: Joi.object({
+        template: Joi.string().required(),
+        options: Joi.object()
+    }),
+
+    value: Joi.object({
+        value: Joi.alternatives([Joi.object(), Joi.array()]).required()
+    })
+};
+
+
+internals.desc.entity = Joi.alternatives([
+    Joi.array().items(Joi.link('...')),
+    Joi.boolean(),
+    Joi.function(),
+    Joi.number(),
+    Joi.string(),
+    internals.desc.buffer,
+    internals.desc.func,
+    internals.desc.ref,
+    internals.desc.regex,
+    internals.desc.special,
+    internals.desc.template,
+    internals.desc.value,
+    Joi.link('/')
+]);
+
+
+internals.desc.values = Joi.array()
+    .items(
+        null,
+        Joi.boolean(),
+        Joi.function(),
+        Joi.number().allow(Infinity, -Infinity),
+        Joi.string().allow(''),
+        Joi.symbol(),
+        internals.desc.buffer,
+        internals.desc.func,
+        internals.desc.override,
+        internals.desc.ref,
+        internals.desc.regex,
+        internals.desc.template,
+        internals.desc.value
+    );
+
+
+internals.desc.messages = Joi.object()
+    .pattern(/.+/, [
+        Joi.string(),
+        internals.desc.template,
+        Joi.object().pattern(/.+/, [Joi.string(), internals.desc.template])
+    ]);
+
+
+exports.description = Joi.object({
+    type: Joi.string().required(),
+    flags: Joi.object({
+        cast: Joi.string(),
+        default: Joi.any(),
+        description: Joi.string(),
+        empty: Joi.link('/'),
+        failover: internals.desc.entity,
+        id: Joi.string(),
+        label: Joi.string(),
+        only: true,
+        presence: ['optional', 'required', 'forbidden'],
+        result: ['raw', 'strip'],
+        strip: Joi.boolean(),
+        unit: Joi.string()
+    })
+        .unknown(),
+    preferences: {
+        allowUnknown: Joi.boolean(),
+        abortEarly: Joi.boolean(),
+        artifacts: Joi.boolean(),
+        cache: Joi.boolean(),
+        convert: Joi.boolean(),
+        dateFormat: ['date', 'iso', 'string', 'time', 'utc'],
+        errors: {
+            escapeHtml: Joi.boolean(),
+            label: ['path', 'key'],
+            language: [
+                Joi.string(),
+                internals.desc.ref
+            ],
+            wrap: {
+                label: internals.wrap,
+                array: internals.wrap
+            }
+        },
+        externals: Joi.boolean(),
+        messages: internals.desc.messages,
+        noDefaults: Joi.boolean(),
+        nonEnumerables: Joi.boolean(),
+        presence: ['required', 'optional', 'forbidden'],
+        skipFunctions: Joi.boolean(),
+        stripUnknown: Joi.object({
+            arrays: Joi.boolean(),
+            objects: Joi.boolean()
+        })
+            .or('arrays', 'objects')
+            .allow(true, false),
+        warnings: Joi.boolean()
+    },
+    allow: internals.desc.values,
+    invalid: internals.desc.values,
+    rules: Joi.array().min(1).items({
+        name: Joi.string().required(),
+        args: Joi.object().min(1),
+        keep: Joi.boolean(),
+        message: [
+            Joi.string(),
+            internals.desc.messages
+        ],
+        warn: Joi.boolean()
+    }),
+
+    // Terms
+
+    keys: Joi.object().pattern(/.*/, Joi.link('/')),
+    link: internals.desc.ref
+})
+    .pattern(/^[a-z]\w*$/, Joi.any());
diff --git a/node_modules/joi/lib/state.js b/node_modules/joi/lib/state.js
new file mode 100644
index 00000000..8db251b7
--- /dev/null
+++ b/node_modules/joi/lib/state.js
@@ -0,0 +1,152 @@
+'use strict';
+
+const Clone = require('@hapi/hoek/lib/clone');
+const Reach = require('@hapi/hoek/lib/reach');
+
+const Common = require('./common');
+
+
+const internals = {
+    value: Symbol('value')
+};
+
+
+module.exports = internals.State = class {
+
+    constructor(path, ancestors, state) {
+
+        this.path = path;
+        this.ancestors = ancestors;                 // [parent, ..., root]
+
+        this.mainstay = state.mainstay;
+        this.schemas = state.schemas;               // [current, ..., root]
+        this.debug = null;
+    }
+
+    localize(path, ancestors = null, schema = null) {
+
+        const state = new internals.State(path, ancestors, this);
+
+        if (schema &&
+            state.schemas) {
+
+            state.schemas = [internals.schemas(schema), ...state.schemas];
+        }
+
+        return state;
+    }
+
+    nest(schema, debug) {
+
+        const state = new internals.State(this.path, this.ancestors, this);
+        state.schemas = state.schemas && [internals.schemas(schema), ...state.schemas];
+        state.debug = debug;
+        return state;
+    }
+
+    shadow(value, reason) {
+
+        this.mainstay.shadow = this.mainstay.shadow || new internals.Shadow();
+        this.mainstay.shadow.set(this.path, value, reason);
+    }
+
+    snapshot() {
+
+        if (this.mainstay.shadow) {
+            this._snapshot = Clone(this.mainstay.shadow.node(this.path));
+        }
+    }
+
+    restore() {
+
+        if (this.mainstay.shadow) {
+            this.mainstay.shadow.override(this.path, this._snapshot);
+            this._snapshot = undefined;
+        }
+    }
+};
+
+
+internals.schemas = function (schema) {
+
+    if (Common.isSchema(schema)) {
+        return { schema };
+    }
+
+    return schema;
+};
+
+
+internals.Shadow = class {
+
+    constructor() {
+
+        this._values = null;
+    }
+
+    set(path, value, reason) {
+
+        if (!path.length) {                                     // No need to store root value
+            return;
+        }
+
+        if (reason === 'strip' &&
+            typeof path[path.length - 1] === 'number') {        // Cannot store stripped array values (due to shift)
+
+            return;
+        }
+
+        this._values = this._values || new Map();
+
+        let node = this._values;
+        for (let i = 0; i < path.length; ++i) {
+            const segment = path[i];
+            let next = node.get(segment);
+            if (!next) {
+                next = new Map();
+                node.set(segment, next);
+            }
+
+            node = next;
+        }
+
+        node[internals.value] = value;
+    }
+
+    get(path) {
+
+        const node = this.node(path);
+        if (node) {
+            return node[internals.value];
+        }
+    }
+
+    node(path) {
+
+        if (!this._values) {
+            return;
+        }
+
+        return Reach(this._values, path, { iterables: true });
+    }
+
+    override(path, node) {
+
+        if (!this._values) {
+            return;
+        }
+
+        const parents = path.slice(0, -1);
+        const own = path[path.length - 1];
+        const parent = Reach(this._values, parents, { iterables: true });
+
+        if (node) {
+            parent.set(own, node);
+            return;
+        }
+
+        if (parent) {
+            parent.delete(own);
+        }
+    }
+};
diff --git a/node_modules/joi/lib/template.js b/node_modules/joi/lib/template.js
new file mode 100644
index 00000000..c21eb70e
--- /dev/null
+++ b/node_modules/joi/lib/template.js
@@ -0,0 +1,427 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+const EscapeHtml = require('@hapi/hoek/lib/escapeHtml');
+const Formula = require('@sideway/formula');
+
+const Common = require('./common');
+const Errors = require('./errors');
+const Ref = require('./ref');
+
+
+const internals = {
+    symbol: Symbol('template'),
+
+    opens: new Array(1000).join('\u0000'),
+    closes: new Array(1000).join('\u0001'),
+
+    dateFormat: {
+        date: Date.prototype.toDateString,
+        iso: Date.prototype.toISOString,
+        string: Date.prototype.toString,
+        time: Date.prototype.toTimeString,
+        utc: Date.prototype.toUTCString
+    }
+};
+
+
+module.exports = exports = internals.Template = class {
+
+    constructor(source, options) {
+
+        Assert(typeof source === 'string', 'Template source must be a string');
+        Assert(!source.includes('\u0000') && !source.includes('\u0001'), 'Template source cannot contain reserved control characters');
+
+        this.source = source;
+        this.rendered = source;
+
+        this._template = null;
+        this._settings = Clone(options);
+
+        this._parse();
+    }
+
+    _parse() {
+
+        // 'text {raw} {{ref}} \\{{ignore}} {{ignore\\}} {{ignore {{ignore}'
+
+        if (!this.source.includes('{')) {
+            return;
+        }
+
+        // Encode escaped \\{{{{{
+
+        const encoded = internals.encode(this.source);
+
+        // Split on first { in each set
+
+        const parts = internals.split(encoded);
+
+        // Process parts
+
+        let refs = false;
+        const processed = [];
+        const head = parts.shift();
+        if (head) {
+            processed.push(head);
+        }
+
+        for (const part of parts) {
+            const raw = part[0] !== '{';
+            const ender = raw ? '}' : '}}';
+            const end = part.indexOf(ender);
+            if (end === -1 ||                               // Ignore non-matching closing
+                part[1] === '{') {                          // Ignore more than two {
+
+                processed.push(`{${internals.decode(part)}`);
+                continue;
+            }
+
+            let variable = part.slice(raw ? 0 : 1, end);
+            const wrapped = variable[0] === ':';
+            if (wrapped) {
+                variable = variable.slice(1);
+            }
+
+            const dynamic = this._ref(internals.decode(variable), { raw, wrapped });
+            processed.push(dynamic);
+            if (typeof dynamic !== 'string') {
+                refs = true;
+            }
+
+            const rest = part.slice(end + ender.length);
+            if (rest) {
+                processed.push(internals.decode(rest));
+            }
+        }
+
+        if (!refs) {
+            this.rendered = processed.join('');
+            return;
+        }
+
+        this._template = processed;
+    }
+
+    static date(date, prefs) {
+
+        return internals.dateFormat[prefs.dateFormat].call(date);
+    }
+
+    describe(options = {}) {
+
+        if (!this._settings &&
+            options.compact) {
+
+            return this.source;
+        }
+
+        const desc = { template: this.source };
+        if (this._settings) {
+            desc.options = this._settings;
+        }
+
+        return desc;
+    }
+
+    static build(desc) {
+
+        return new internals.Template(desc.template, desc.options);
+    }
+
+    isDynamic() {
+
+        return !!this._template;
+    }
+
+    static isTemplate(template) {
+
+        return template ? !!template[Common.symbols.template] : false;
+    }
+
+    refs() {
+
+        if (!this._template) {
+            return;
+        }
+
+        const refs = [];
+        for (const part of this._template) {
+            if (typeof part !== 'string') {
+                refs.push(...part.refs);
+            }
+        }
+
+        return refs;
+    }
+
+    resolve(value, state, prefs, local) {
+
+        if (this._template &&
+            this._template.length === 1) {
+
+            return this._part(this._template[0], /* context -> [*/ value, state, prefs, local, {} /*] */);
+        }
+
+        return this.render(value, state, prefs, local);
+    }
+
+    _part(part, ...args) {
+
+        if (part.ref) {
+            return part.ref.resolve(...args);
+        }
+
+        return part.formula.evaluate(args);
+    }
+
+    render(value, state, prefs, local, options = {}) {
+
+        if (!this.isDynamic()) {
+            return this.rendered;
+        }
+
+        const parts = [];
+        for (const part of this._template) {
+            if (typeof part === 'string') {
+                parts.push(part);
+            }
+            else {
+                const rendered = this._part(part, /* context -> [*/ value, state, prefs, local, options /*] */);
+                const string = internals.stringify(rendered, value, state, prefs, local, options);
+                if (string !== undefined) {
+                    const result = part.raw || (options.errors && options.errors.escapeHtml) === false ? string : EscapeHtml(string);
+                    parts.push(internals.wrap(result, part.wrapped && prefs.errors.wrap.label));
+                }
+            }
+        }
+
+        return parts.join('');
+    }
+
+    _ref(content, { raw, wrapped }) {
+
+        const refs = [];
+        const reference = (variable) => {
+
+            const ref = Ref.create(variable, this._settings);
+            refs.push(ref);
+            return (context) => ref.resolve(...context);
+        };
+
+        try {
+            var formula = new Formula.Parser(content, { reference, functions: internals.functions, constants: internals.constants });
+        }
+        catch (err) {
+            err.message = `Invalid template variable "${content}" fails due to: ${err.message}`;
+            throw err;
+        }
+
+        if (formula.single) {
+            if (formula.single.type === 'reference') {
+                const ref = refs[0];
+                return { ref, raw, refs, wrapped: wrapped || ref.type === 'local' && ref.key === 'label' };
+            }
+
+            return internals.stringify(formula.single.value);
+        }
+
+        return { formula, raw, refs };
+    }
+
+    toString() {
+
+        return this.source;
+    }
+};
+
+
+internals.Template.prototype[Common.symbols.template] = true;
+internals.Template.prototype.isImmutable = true;                // Prevents Hoek from deep cloning schema objects
+
+
+internals.encode = function (string) {
+
+    return string
+        .replace(/\\(\{+)/g, ($0, $1) => {
+
+            return internals.opens.slice(0, $1.length);
+        })
+        .replace(/\\(\}+)/g, ($0, $1) => {
+
+            return internals.closes.slice(0, $1.length);
+        });
+};
+
+
+internals.decode = function (string) {
+
+    return string
+        .replace(/\u0000/g, '{')
+        .replace(/\u0001/g, '}');
+};
+
+
+internals.split = function (string) {
+
+    const parts = [];
+    let current = '';
+
+    for (let i = 0; i < string.length; ++i) {
+        const char = string[i];
+
+        if (char === '{') {
+            let next = '';
+            while (i + 1 < string.length &&
+                string[i + 1] === '{') {
+
+                next += '{';
+                ++i;
+            }
+
+            parts.push(current);
+            current = next;
+        }
+        else {
+            current += char;
+        }
+    }
+
+    parts.push(current);
+    return parts;
+};
+
+
+internals.wrap = function (value, ends) {
+
+    if (!ends) {
+        return value;
+    }
+
+    if (ends.length === 1) {
+        return `${ends}${value}${ends}`;
+    }
+
+    return `${ends[0]}${value}${ends[1]}`;
+};
+
+
+internals.stringify = function (value, original, state, prefs, local, options) {
+
+    const type = typeof value;
+
+    let skipWrap = false;
+    if (Ref.isRef(value) &&
+        value.render) {
+
+        skipWrap = value.in;
+        value = value.resolve(original, state, prefs, local, { in: value.in, ...options });
+    }
+
+    if (value === null) {
+        return 'null';
+    }
+
+    if (type === 'string') {
+        return value;
+    }
+
+    if (type === 'number' ||
+        type === 'function' ||
+        type === 'symbol') {
+
+        return value.toString();
+    }
+
+    if (type !== 'object') {
+        return JSON.stringify(value);
+    }
+
+    if (value instanceof Date) {
+        return internals.Template.date(value, prefs);
+    }
+
+    if (value instanceof Map) {
+        const pairs = [];
+        for (const [key, sym] of value.entries()) {
+            pairs.push(`${key.toString()} -> ${sym.toString()}`);
+        }
+
+        value = pairs;
+    }
+
+    if (!Array.isArray(value)) {
+        return value.toString();
+    }
+
+    let partial = '';
+    for (const item of value) {
+        partial = partial + (partial.length ? ', ' : '') + internals.stringify(item, original, state, prefs, local, options);
+    }
+
+    if (skipWrap) {
+        return partial;
+    }
+
+    return internals.wrap(partial, prefs.errors.wrap.array);
+};
+
+
+internals.constants = {
+
+    true: true,
+    false: false,
+    null: null,
+
+    second: 1000,
+    minute: 60 * 1000,
+    hour: 60 * 60 * 1000,
+    day: 24 * 60 * 60 * 1000
+};
+
+
+internals.functions = {
+
+    if(condition, then, otherwise) {
+
+        return condition ? then : otherwise;
+    },
+
+    msg(code) {
+
+        const [value, state, prefs, local, options] = this;
+        const messages = options.messages;
+        if (!messages) {
+            return '';
+        }
+
+        const template = Errors.template(value, messages[0], code, state, prefs) || Errors.template(value, messages[1], code, state, prefs);
+        if (!template) {
+            return '';
+        }
+
+        return template.render(value, state, prefs, local, options);
+    },
+
+    number(value) {
+
+        if (typeof value === 'number') {
+            return value;
+        }
+
+        if (typeof value === 'string') {
+            return parseFloat(value);
+        }
+
+        if (typeof value === 'boolean') {
+            return value ? 1 : 0;
+        }
+
+        if (value instanceof Date) {
+            return value.getTime();
+        }
+
+        return null;
+    }
+};
diff --git a/node_modules/joi/lib/trace.js b/node_modules/joi/lib/trace.js
new file mode 100644
index 00000000..ded4d7e7
--- /dev/null
+++ b/node_modules/joi/lib/trace.js
@@ -0,0 +1,346 @@
+'use strict';
+
+const DeepEqual = require('@hapi/hoek/lib/deepEqual');
+const Pinpoint = require('@sideway/pinpoint');
+
+const Errors = require('./errors');
+
+
+const internals = {
+    codes: {
+        error: 1,
+        pass: 2,
+        full: 3
+    },
+    labels: {
+        0: 'never used',
+        1: 'always error',
+        2: 'always pass'
+    }
+};
+
+
+exports.setup = function (root) {
+
+    const trace = function () {
+
+        root._tracer = root._tracer || new internals.Tracer();
+        return root._tracer;
+    };
+
+    root.trace = trace;
+    root[Symbol.for('@hapi/lab/coverage/initialize')] = trace;
+
+    root.untrace = () => {
+
+        root._tracer = null;
+    };
+};
+
+
+exports.location = function (schema) {
+
+    return schema.$_setFlag('_tracerLocation', Pinpoint.location(2));                       // base.tracer(), caller
+};
+
+
+internals.Tracer = class {
+
+    constructor() {
+
+        this.name = 'Joi';
+        this._schemas = new Map();
+    }
+
+    _register(schema) {
+
+        const existing = this._schemas.get(schema);
+        if (existing) {
+            return existing.store;
+        }
+
+        const store = new internals.Store(schema);
+        const { filename, line } = schema._flags._tracerLocation || Pinpoint.location(5);   // internals.tracer(), internals.entry(), exports.entry(), validate(), caller
+        this._schemas.set(schema, { filename, line, store });
+        return store;
+    }
+
+    _combine(merged, sources) {
+
+        for (const { store } of this._schemas.values()) {
+            store._combine(merged, sources);
+        }
+    }
+
+    report(file) {
+
+        const coverage = [];
+
+        // Process each registered schema
+
+        for (const { filename, line, store } of this._schemas.values()) {
+            if (file &&
+                file !== filename) {
+
+                continue;
+            }
+
+            // Process sub schemas of the registered root
+
+            const missing = [];
+            const skipped = [];
+
+            for (const [schema, log] of store._sources.entries()) {
+
+                // Check if sub schema parent skipped
+
+                if (internals.sub(log.paths, skipped)) {
+                    continue;
+                }
+
+                // Check if sub schema reached
+
+                if (!log.entry) {
+                    missing.push({
+                        status: 'never reached',
+                        paths: [...log.paths]
+                    });
+
+                    skipped.push(...log.paths);
+                    continue;
+                }
+
+                // Check values
+
+                for (const type of ['valid', 'invalid']) {
+                    const set = schema[`_${type}s`];
+                    if (!set) {
+                        continue;
+                    }
+
+                    const values = new Set(set._values);
+                    const refs = new Set(set._refs);
+                    for (const { value, ref } of log[type]) {
+                        values.delete(value);
+                        refs.delete(ref);
+                    }
+
+                    if (values.size ||
+                        refs.size) {
+
+                        missing.push({
+                            status: [...values, ...[...refs].map((ref) => ref.display)],
+                            rule: `${type}s`
+                        });
+                    }
+                }
+
+                // Check rules status
+
+                const rules = schema._rules.map((rule) => rule.name);
+                for (const type of ['default', 'failover']) {
+                    if (schema._flags[type] !== undefined) {
+                        rules.push(type);
+                    }
+                }
+
+                for (const name of rules) {
+                    const status = internals.labels[log.rule[name] || 0];
+                    if (status) {
+                        const report = { rule: name, status };
+                        if (log.paths.size) {
+                            report.paths = [...log.paths];
+                        }
+
+                        missing.push(report);
+                    }
+                }
+            }
+
+            if (missing.length) {
+                coverage.push({
+                    filename,
+                    line,
+                    missing,
+                    severity: 'error',
+                    message: `Schema missing tests for ${missing.map(internals.message).join(', ')}`
+                });
+            }
+        }
+
+        return coverage.length ? coverage : null;
+    }
+};
+
+
+internals.Store = class {
+
+    constructor(schema) {
+
+        this.active = true;
+        this._sources = new Map();          // schema -> { paths, entry, rule, valid, invalid }
+        this._combos = new Map();           // merged -> [sources]
+        this._scan(schema);
+    }
+
+    debug(state, source, name, result) {
+
+        state.mainstay.debug && state.mainstay.debug.push({ type: source, name, result, path: state.path });
+    }
+
+    entry(schema, state) {
+
+        internals.debug(state, { type: 'entry' });
+
+        this._record(schema, (log) => {
+
+            log.entry = true;
+        });
+    }
+
+    filter(schema, state, source, value) {
+
+        internals.debug(state, { type: source, ...value });
+
+        this._record(schema, (log) => {
+
+            log[source].add(value);
+        });
+    }
+
+    log(schema, state, source, name, result) {
+
+        internals.debug(state, { type: source, name, result: result === 'full' ? 'pass' : result });
+
+        this._record(schema, (log) => {
+
+            log[source][name] = log[source][name] || 0;
+            log[source][name] |= internals.codes[result];
+        });
+    }
+
+    resolve(state, ref, to) {
+
+        if (!state.mainstay.debug) {
+            return;
+        }
+
+        const log = { type: 'resolve', ref: ref.display, to, path: state.path };
+        state.mainstay.debug.push(log);
+    }
+
+    value(state, by, from, to, name) {
+
+        if (!state.mainstay.debug ||
+            DeepEqual(from, to)) {
+
+            return;
+        }
+
+        const log = { type: 'value', by, from, to, path: state.path };
+        if (name) {
+            log.name = name;
+        }
+
+        state.mainstay.debug.push(log);
+    }
+
+    _record(schema, each) {
+
+        const log = this._sources.get(schema);
+        if (log) {
+            each(log);
+            return;
+        }
+
+        const sources = this._combos.get(schema);
+        for (const source of sources) {
+            this._record(source, each);
+        }
+    }
+
+    _scan(schema, _path) {
+
+        const path = _path || [];
+
+        let log = this._sources.get(schema);
+        if (!log) {
+            log = {
+                paths: new Set(),
+                entry: false,
+                rule: {},
+                valid: new Set(),
+                invalid: new Set()
+            };
+
+            this._sources.set(schema, log);
+        }
+
+        if (path.length) {
+            log.paths.add(path);
+        }
+
+        const each = (sub, source) => {
+
+            const subId = internals.id(sub, source);
+            this._scan(sub, path.concat(subId));
+        };
+
+        schema.$_modify({ each, ref: false });
+    }
+
+    _combine(merged, sources) {
+
+        this._combos.set(merged, sources);
+    }
+};
+
+
+internals.message = function (item) {
+
+    const path = item.paths ? Errors.path(item.paths[0]) + (item.rule ? ':' : '') : '';
+    return `${path}${item.rule || ''} (${item.status})`;
+};
+
+
+internals.id = function (schema, { source, name, path, key }) {
+
+    if (schema._flags.id) {
+        return schema._flags.id;
+    }
+
+    if (key) {
+        return key;
+    }
+
+    name = `@${name}`;
+
+    if (source === 'terms') {
+        return [name, path[Math.min(path.length - 1, 1)]];
+    }
+
+    return name;
+};
+
+
+internals.sub = function (paths, skipped) {
+
+    for (const path of paths) {
+        for (const skip of skipped) {
+            if (DeepEqual(path.slice(0, skip.length), skip)) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+};
+
+
+internals.debug = function (state, event) {
+
+    if (state.mainstay.debug) {
+        event.path = state.debug ? [...state.path, state.debug] : state.path;
+        state.mainstay.debug.push(event);
+    }
+};
diff --git a/node_modules/joi/lib/types/alternatives.js b/node_modules/joi/lib/types/alternatives.js
new file mode 100644
index 00000000..940c6697
--- /dev/null
+++ b/node_modules/joi/lib/types/alternatives.js
@@ -0,0 +1,329 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+const Common = require('../common');
+const Compile = require('../compile');
+const Errors = require('../errors');
+const Ref = require('../ref');
+
+
+const internals = {};
+
+
+module.exports = Any.extend({
+
+    type: 'alternatives',
+
+    flags: {
+
+        match: { default: 'any' }                 // 'any', 'one', 'all'
+    },
+
+    terms: {
+
+        matches: { init: [], register: Ref.toSibling }
+    },
+
+    args(schema, ...schemas) {
+
+        if (schemas.length === 1) {
+            if (Array.isArray(schemas[0])) {
+                return schema.try(...schemas[0]);
+            }
+        }
+
+        return schema.try(...schemas);
+    },
+
+    validate(value, helpers) {
+
+        const { schema, error, state, prefs } = helpers;
+
+        // Match all or one
+
+        if (schema._flags.match) {
+            let hits = 0;
+            let matched;
+
+            for (let i = 0; i < schema.$_terms.matches.length; ++i) {
+                const item = schema.$_terms.matches[i];
+                const localState = state.nest(item.schema, `match.${i}`);
+                localState.snapshot();
+
+                const result = item.schema.$_validate(value, localState, prefs);
+                if (!result.errors) {
+                    ++hits;
+                    matched = result.value;
+                }
+                else {
+                    localState.restore();
+                }
+            }
+
+            if (!hits) {
+                return { errors: error('alternatives.any') };
+            }
+
+            if (schema._flags.match === 'one') {
+                return hits === 1 ? { value: matched } : { errors: error('alternatives.one') };
+            }
+
+            return hits === schema.$_terms.matches.length ? { value } : { errors: error('alternatives.all') };
+        }
+
+        // Match any
+
+        const errors = [];
+        for (let i = 0; i < schema.$_terms.matches.length; ++i) {
+            const item = schema.$_terms.matches[i];
+
+            // Try
+
+            if (item.schema) {
+                const localState = state.nest(item.schema, `match.${i}`);
+                localState.snapshot();
+
+                const result = item.schema.$_validate(value, localState, prefs);
+                if (!result.errors) {
+                    return result;
+                }
+
+                localState.restore();
+                errors.push({ schema: item.schema, reports: result.errors });
+                continue;
+            }
+
+            // Conditional
+
+            const input = item.ref ? item.ref.resolve(value, state, prefs) : value;
+            const tests = item.is ? [item] : item.switch;
+
+            for (let j = 0; j < tests.length; ++j) {
+                const test = tests[j];
+                const { is, then, otherwise } = test;
+
+                const id = `match.${i}${item.switch ? '.' + j : ''}`;
+                if (!is.$_match(input, state.nest(is, `${id}.is`), prefs)) {
+                    if (otherwise) {
+                        return otherwise.$_validate(value, state.nest(otherwise, `${id}.otherwise`), prefs);
+                    }
+                }
+                else if (then) {
+                    return then.$_validate(value, state.nest(then, `${id}.then`), prefs);
+                }
+            }
+        }
+
+        return internals.errors(errors, helpers);
+    },
+
+    rules: {
+
+        conditional: {
+            method(condition, options) {
+
+                Assert(!this._flags._endedSwitch, 'Unreachable condition');
+                Assert(!this._flags.match, 'Cannot combine match mode', this._flags.match, 'with conditional rule');
+                Assert(options.break === undefined, 'Cannot use break option with alternatives conditional');
+
+                const obj = this.clone();
+
+                const match = Compile.when(obj, condition, options);
+                const conditions = match.is ? [match] : match.switch;
+                for (const item of conditions) {
+                    if (item.then &&
+                        item.otherwise) {
+
+                        obj.$_setFlag('_endedSwitch', true, { clone: false });
+                        break;
+                    }
+                }
+
+                obj.$_terms.matches.push(match);
+                return obj.$_mutateRebuild();
+            }
+        },
+
+        match: {
+            method(mode) {
+
+                Assert(['any', 'one', 'all'].includes(mode), 'Invalid alternatives match mode', mode);
+
+                if (mode !== 'any') {
+                    for (const match of this.$_terms.matches) {
+                        Assert(match.schema, 'Cannot combine match mode', mode, 'with conditional rules');
+                    }
+                }
+
+                return this.$_setFlag('match', mode);
+            }
+        },
+
+        try: {
+            method(...schemas) {
+
+                Assert(schemas.length, 'Missing alternative schemas');
+                Common.verifyFlat(schemas, 'try');
+
+                Assert(!this._flags._endedSwitch, 'Unreachable condition');
+
+                const obj = this.clone();
+                for (const schema of schemas) {
+                    obj.$_terms.matches.push({ schema: obj.$_compile(schema) });
+                }
+
+                return obj.$_mutateRebuild();
+            }
+        }
+    },
+
+    overrides: {
+
+        label(name) {
+
+            const obj = this.$_parent('label', name);
+            const each = (item, source) => (source.path[0] !== 'is' ? item.label(name) : undefined);
+            return obj.$_modify({ each, ref: false });
+        }
+    },
+
+    rebuild(schema) {
+
+        // Flag when an alternative type is an array
+
+        const each = (item) => {
+
+            if (Common.isSchema(item) &&
+                item.type === 'array') {
+
+                schema.$_setFlag('_arrayItems', true, { clone: false });
+            }
+        };
+
+        schema.$_modify({ each });
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            if (desc.matches) {
+                for (const match of desc.matches) {
+                    const { schema, ref, is, not, then, otherwise } = match;
+                    if (schema) {
+                        obj = obj.try(schema);
+                    }
+                    else if (ref) {
+                        obj = obj.conditional(ref, { is, then, not, otherwise, switch: match.switch });
+                    }
+                    else {
+                        obj = obj.conditional(is, { then, otherwise });
+                    }
+                }
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'alternatives.all': '{{#label}} does not match all of the required types',
+        'alternatives.any': '{{#label}} does not match any of the allowed types',
+        'alternatives.match': '{{#label}} does not match any of the allowed types',
+        'alternatives.one': '{{#label}} matches more than one allowed type',
+        'alternatives.types': '{{#label}} must be one of {{#types}}'
+    }
+});
+
+
+// Helpers
+
+internals.errors = function (failures, { error, state }) {
+
+    // Nothing matched due to type criteria rules
+
+    if (!failures.length) {
+        return { errors: error('alternatives.any') };
+    }
+
+    // Single error
+
+    if (failures.length === 1) {
+        return { errors: failures[0].reports };
+    }
+
+    // Analyze reasons
+
+    const valids = new Set();
+    const complex = [];
+
+    for (const { reports, schema } of failures) {
+
+        // Multiple errors (!abortEarly)
+
+        if (reports.length > 1) {
+            return internals.unmatched(failures, error);
+        }
+
+        // Custom error
+
+        const report = reports[0];
+        if (report instanceof Errors.Report === false) {
+            return internals.unmatched(failures, error);
+        }
+
+        // Internal object or array error
+
+        if (report.state.path.length !== state.path.length) {
+            complex.push({ type: schema.type, report });
+            continue;
+        }
+
+        // Valids
+
+        if (report.code === 'any.only') {
+            for (const valid of report.local.valids) {
+                valids.add(valid);
+            }
+
+            continue;
+        }
+
+        // Base type
+
+        const [type, code] = report.code.split('.');
+        if (code !== 'base') {
+            complex.push({ type: schema.type, report });
+            continue;
+        }
+
+        valids.add(type);
+    }
+
+    // All errors are base types or valids
+
+    if (!complex.length) {
+        return { errors: error('alternatives.types', { types: [...valids] }) };
+    }
+
+    // Single complex error
+
+    if (complex.length === 1) {
+        return { errors: complex[0].report };
+    }
+
+    return internals.unmatched(failures, error);
+};
+
+
+internals.unmatched = function (failures, error) {
+
+    const errors = [];
+    for (const failure of failures) {
+        errors.push(...failure.reports);
+    }
+
+    return { errors: error('alternatives.match', Errors.details(errors, { override: false })) };
+};
diff --git a/node_modules/joi/lib/types/any.js b/node_modules/joi/lib/types/any.js
new file mode 100644
index 00000000..2b1ad58b
--- /dev/null
+++ b/node_modules/joi/lib/types/any.js
@@ -0,0 +1,174 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Base = require('../base');
+const Common = require('../common');
+const Messages = require('../messages');
+
+
+const internals = {};
+
+
+module.exports = Base.extend({
+
+    type: 'any',
+
+    flags: {
+
+        only: { default: false }
+    },
+
+    terms: {
+
+        alterations: { init: null },
+        examples: { init: null },
+        externals: { init: null },
+        metas: { init: [] },
+        notes: { init: [] },
+        shared: { init: null },
+        tags: { init: [] },
+        whens: { init: null }
+    },
+
+    rules: {
+
+        custom: {
+            method(method, description) {
+
+                Assert(typeof method === 'function', 'Method must be a function');
+                Assert(description === undefined || description && typeof description === 'string', 'Description must be a non-empty string');
+
+                return this.$_addRule({ name: 'custom', args: { method, description } });
+            },
+            validate(value, helpers, { method }) {
+
+                try {
+                    return method(value, helpers);
+                }
+                catch (err) {
+                    return helpers.error('any.custom', { error: err });
+                }
+            },
+            args: ['method', 'description'],
+            multi: true
+        },
+
+        messages: {
+            method(messages) {
+
+                return this.prefs({ messages });
+            }
+        },
+
+        shared: {
+            method(schema) {
+
+                Assert(Common.isSchema(schema) && schema._flags.id, 'Schema must be a schema with an id');
+
+                const obj = this.clone();
+                obj.$_terms.shared = obj.$_terms.shared || [];
+                obj.$_terms.shared.push(schema);
+                obj.$_mutateRegister(schema);
+                return obj;
+            }
+        },
+
+        warning: {
+            method(code, local) {
+
+                Assert(code && typeof code === 'string', 'Invalid warning code');
+
+                return this.$_addRule({ name: 'warning', args: { code, local }, warn: true });
+            },
+            validate(value, helpers, { code, local }) {
+
+                return helpers.error(code, local);
+            },
+            args: ['code', 'local'],
+            multi: true
+        }
+    },
+
+    modifiers: {
+
+        keep(rule, enabled = true) {
+
+            rule.keep = enabled;
+        },
+
+        message(rule, message) {
+
+            rule.message = Messages.compile(message);
+        },
+
+        warn(rule, enabled = true) {
+
+            rule.warn = enabled;
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            for (const key in desc) {
+                const values = desc[key];
+
+                if (['examples', 'externals', 'metas', 'notes', 'tags'].includes(key)) {
+                    for (const value of values) {
+                        obj = obj[key.slice(0, -1)](value);
+                    }
+
+                    continue;
+                }
+
+                if (key === 'alterations') {
+                    const alter = {};
+                    for (const { target, adjuster } of values) {
+                        alter[target] = adjuster;
+                    }
+
+                    obj = obj.alter(alter);
+                    continue;
+                }
+
+                if (key === 'whens') {
+                    for (const value of values) {
+                        const { ref, is, not, then, otherwise, concat } = value;
+                        if (concat) {
+                            obj = obj.concat(concat);
+                        }
+                        else if (ref) {
+                            obj = obj.when(ref, { is, not, then, otherwise, switch: value.switch, break: value.break });
+                        }
+                        else {
+                            obj = obj.when(is, { then, otherwise, break: value.break });
+                        }
+                    }
+
+                    continue;
+                }
+
+                if (key === 'shared') {
+                    for (const value of values) {
+                        obj = obj.shared(value);
+                    }
+                }
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'any.custom': '{{#label}} failed custom validation because {{#error.message}}',
+        'any.default': '{{#label}} threw an error when running default method',
+        'any.failover': '{{#label}} threw an error when running failover method',
+        'any.invalid': '{{#label}} contains an invalid value',
+        'any.only': '{{#label}} must be {if(#valids.length == 1, "", "one of ")}{{#valids}}',
+        'any.ref': '{{#label}} {{#arg}} references {{:#ref}} which {{#reason}}',
+        'any.required': '{{#label}} is required',
+        'any.unknown': '{{#label}} is not allowed'
+    }
+});
diff --git a/node_modules/joi/lib/types/array.js b/node_modules/joi/lib/types/array.js
new file mode 100644
index 00000000..a18d558f
--- /dev/null
+++ b/node_modules/joi/lib/types/array.js
@@ -0,0 +1,775 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const DeepEqual = require('@hapi/hoek/lib/deepEqual');
+const Reach = require('@hapi/hoek/lib/reach');
+
+const Any = require('./any');
+const Common = require('../common');
+const Compile = require('../compile');
+
+
+const internals = {};
+
+
+module.exports = Any.extend({
+
+    type: 'array',
+
+    flags: {
+
+        single: { default: false },
+        sparse: { default: false }
+    },
+
+    terms: {
+
+        items: { init: [], manifest: 'schema' },
+        ordered: { init: [], manifest: 'schema' },
+
+        _exclusions: { init: [] },
+        _inclusions: { init: [] },
+        _requireds: { init: [] }
+    },
+
+    coerce: {
+        from: 'object',
+        method(value, { schema, state, prefs }) {
+
+            if (!Array.isArray(value)) {
+                return;
+            }
+
+            const sort = schema.$_getRule('sort');
+            if (!sort) {
+                return;
+            }
+
+            return internals.sort(schema, value, sort.args.options, state, prefs);
+        }
+    },
+
+    validate(value, { schema, error }) {
+
+        if (!Array.isArray(value)) {
+            if (schema._flags.single) {
+                const single = [value];
+                single[Common.symbols.arraySingle] = true;
+                return { value: single };
+            }
+
+            return { errors: error('array.base') };
+        }
+
+        if (!schema.$_getRule('items') &&
+            !schema.$_terms.externals) {
+
+            return;
+        }
+
+        return { value: value.slice() };        // Clone the array so that we don't modify the original
+    },
+
+    rules: {
+
+        has: {
+            method(schema) {
+
+                schema = this.$_compile(schema, { appendPath: true });
+                const obj = this.$_addRule({ name: 'has', args: { schema } });
+                obj.$_mutateRegister(schema);
+                return obj;
+            },
+            validate(value, { state, prefs, error }, { schema: has }) {
+
+                const ancestors = [value, ...state.ancestors];
+                for (let i = 0; i < value.length; ++i) {
+                    const localState = state.localize([...state.path, i], ancestors, has);
+                    if (has.$_match(value[i], localState, prefs)) {
+                        return value;
+                    }
+                }
+
+                const patternLabel = has._flags.label;
+                if (patternLabel) {
+                    return error('array.hasKnown', { patternLabel });
+                }
+
+                return error('array.hasUnknown', null);
+            },
+            multi: true
+        },
+
+        items: {
+            method(...schemas) {
+
+                Common.verifyFlat(schemas, 'items');
+
+                const obj = this.$_addRule('items');
+
+                for (let i = 0; i < schemas.length; ++i) {
+                    const type = Common.tryWithPath(() => this.$_compile(schemas[i]), i, { append: true });
+                    obj.$_terms.items.push(type);
+                }
+
+                return obj.$_mutateRebuild();
+            },
+            validate(value, { schema, error, state, prefs, errorsArray }) {
+
+                const requireds = schema.$_terms._requireds.slice();
+                const ordereds = schema.$_terms.ordered.slice();
+                const inclusions = [...schema.$_terms._inclusions, ...requireds];
+
+                const wasArray = !value[Common.symbols.arraySingle];
+                delete value[Common.symbols.arraySingle];
+
+                const errors = errorsArray();
+
+                let il = value.length;
+                for (let i = 0; i < il; ++i) {
+                    const item = value[i];
+
+                    let errored = false;
+                    let isValid = false;
+
+                    const key = wasArray ? i : new Number(i);       // eslint-disable-line no-new-wrappers
+                    const path = [...state.path, key];
+
+                    // Sparse
+
+                    if (!schema._flags.sparse &&
+                        item === undefined) {
+
+                        errors.push(error('array.sparse', { key, path, pos: i, value: undefined }, state.localize(path)));
+                        if (prefs.abortEarly) {
+                            return errors;
+                        }
+
+                        ordereds.shift();
+                        continue;
+                    }
+
+                    // Exclusions
+
+                    const ancestors = [value, ...state.ancestors];
+
+                    for (const exclusion of schema.$_terms._exclusions) {
+                        if (!exclusion.$_match(item, state.localize(path, ancestors, exclusion), prefs, { presence: 'ignore' })) {
+                            continue;
+                        }
+
+                        errors.push(error('array.excludes', { pos: i, value: item }, state.localize(path)));
+                        if (prefs.abortEarly) {
+                            return errors;
+                        }
+
+                        errored = true;
+                        ordereds.shift();
+                        break;
+                    }
+
+                    if (errored) {
+                        continue;
+                    }
+
+                    // Ordered
+
+                    if (schema.$_terms.ordered.length) {
+                        if (ordereds.length) {
+                            const ordered = ordereds.shift();
+                            const res = ordered.$_validate(item, state.localize(path, ancestors, ordered), prefs);
+                            if (!res.errors) {
+                                if (ordered._flags.result === 'strip') {
+                                    internals.fastSplice(value, i);
+                                    --i;
+                                    --il;
+                                }
+                                else if (!schema._flags.sparse && res.value === undefined) {
+                                    errors.push(error('array.sparse', { key, path, pos: i, value: undefined }, state.localize(path)));
+                                    if (prefs.abortEarly) {
+                                        return errors;
+                                    }
+
+                                    continue;
+                                }
+                                else {
+                                    value[i] = res.value;
+                                }
+                            }
+                            else {
+                                errors.push(...res.errors);
+                                if (prefs.abortEarly) {
+                                    return errors;
+                                }
+                            }
+
+                            continue;
+                        }
+                        else if (!schema.$_terms.items.length) {
+                            errors.push(error('array.orderedLength', { pos: i, limit: schema.$_terms.ordered.length }));
+                            if (prefs.abortEarly) {
+                                return errors;
+                            }
+
+                            break;      // No reason to continue since there are no other rules to validate other than array.orderedLength
+                        }
+                    }
+
+                    // Requireds
+
+                    const requiredChecks = [];
+                    let jl = requireds.length;
+                    for (let j = 0; j < jl; ++j) {
+                        const localState = state.localize(path, ancestors, requireds[j]);
+                        localState.snapshot();
+
+                        const res = requireds[j].$_validate(item, localState, prefs);
+                        requiredChecks[j] = res;
+
+                        if (!res.errors) {
+                            value[i] = res.value;
+                            isValid = true;
+                            internals.fastSplice(requireds, j);
+                            --j;
+                            --jl;
+
+                            if (!schema._flags.sparse &&
+                                res.value === undefined) {
+
+                                errors.push(error('array.sparse', { key, path, pos: i, value: undefined }, state.localize(path)));
+                                if (prefs.abortEarly) {
+                                    return errors;
+                                }
+                            }
+
+                            break;
+                        }
+
+                        localState.restore();
+                    }
+
+                    if (isValid) {
+                        continue;
+                    }
+
+                    // Inclusions
+
+                    const stripUnknown = prefs.stripUnknown && !!prefs.stripUnknown.arrays || false;
+
+                    jl = inclusions.length;
+                    for (const inclusion of inclusions) {
+
+                        // Avoid re-running requireds that already didn't match in the previous loop
+
+                        let res;
+                        const previousCheck = requireds.indexOf(inclusion);
+                        if (previousCheck !== -1) {
+                            res = requiredChecks[previousCheck];
+                        }
+                        else {
+                            const localState = state.localize(path, ancestors, inclusion);
+                            localState.snapshot();
+
+                            res = inclusion.$_validate(item, localState, prefs);
+                            if (!res.errors) {
+                                if (inclusion._flags.result === 'strip') {
+                                    internals.fastSplice(value, i);
+                                    --i;
+                                    --il;
+                                }
+                                else if (!schema._flags.sparse &&
+                                    res.value === undefined) {
+
+                                    errors.push(error('array.sparse', { key, path, pos: i, value: undefined }, state.localize(path)));
+                                    errored = true;
+                                }
+                                else {
+                                    value[i] = res.value;
+                                }
+
+                                isValid = true;
+                                break;
+                            }
+
+                            localState.restore();
+                        }
+
+                        // Return the actual error if only one inclusion defined
+
+                        if (jl === 1) {
+                            if (stripUnknown) {
+                                internals.fastSplice(value, i);
+                                --i;
+                                --il;
+                                isValid = true;
+                                break;
+                            }
+
+                            errors.push(...res.errors);
+                            if (prefs.abortEarly) {
+                                return errors;
+                            }
+
+                            errored = true;
+                            break;
+                        }
+                    }
+
+                    if (errored) {
+                        continue;
+                    }
+
+                    if (schema.$_terms._inclusions.length &&
+                        !isValid) {
+
+                        if (stripUnknown) {
+                            internals.fastSplice(value, i);
+                            --i;
+                            --il;
+                            continue;
+                        }
+
+                        errors.push(error('array.includes', { pos: i, value: item }, state.localize(path)));
+                        if (prefs.abortEarly) {
+                            return errors;
+                        }
+                    }
+                }
+
+                if (requireds.length) {
+                    internals.fillMissedErrors(schema, errors, requireds, value, state, prefs);
+                }
+
+                if (ordereds.length) {
+                    internals.fillOrderedErrors(schema, errors, ordereds, value, state, prefs);
+                }
+
+                return errors.length ? errors : value;
+            },
+
+            priority: true,
+            manifest: false
+        },
+
+        length: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'length', args: { limit }, operator: '=' });
+            },
+            validate(value, helpers, { limit }, { name, operator, args }) {
+
+                if (Common.compare(value.length, limit, operator)) {
+                    return value;
+                }
+
+                return helpers.error('array.' + name, { limit: args.limit, value });
+            },
+            args: [
+                {
+                    name: 'limit',
+                    ref: true,
+                    assert: Common.limit,
+                    message: 'must be a positive integer'
+                }
+            ]
+        },
+
+        max: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'max', method: 'length', args: { limit }, operator: '<=' });
+            }
+        },
+
+        min: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'min', method: 'length', args: { limit }, operator: '>=' });
+            }
+        },
+
+        ordered: {
+            method(...schemas) {
+
+                Common.verifyFlat(schemas, 'ordered');
+
+                const obj = this.$_addRule('items');
+
+                for (let i = 0; i < schemas.length; ++i) {
+                    const type = Common.tryWithPath(() => this.$_compile(schemas[i]), i, { append: true });
+                    internals.validateSingle(type, obj);
+
+                    obj.$_mutateRegister(type);
+                    obj.$_terms.ordered.push(type);
+                }
+
+                return obj.$_mutateRebuild();
+            }
+        },
+
+        single: {
+            method(enabled) {
+
+                const value = enabled === undefined ? true : !!enabled;
+                Assert(!value || !this._flags._arrayItems, 'Cannot specify single rule when array has array items');
+
+                return this.$_setFlag('single', value);
+            }
+        },
+
+        sort: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['by', 'order']);
+
+                const settings = {
+                    order: options.order || 'ascending'
+                };
+
+                if (options.by) {
+                    settings.by = Compile.ref(options.by, { ancestor: 0 });
+                    Assert(!settings.by.ancestor, 'Cannot sort by ancestor');
+                }
+
+                return this.$_addRule({ name: 'sort', args: { options: settings } });
+            },
+            validate(value, { error, state, prefs, schema }, { options }) {
+
+                const { value: sorted, errors } = internals.sort(schema, value, options, state, prefs);
+                if (errors) {
+                    return errors;
+                }
+
+                for (let i = 0; i < value.length; ++i) {
+                    if (value[i] !== sorted[i]) {
+                        return error('array.sort', { order: options.order, by: options.by ? options.by.key : 'value' });
+                    }
+                }
+
+                return value;
+            },
+            convert: true
+        },
+
+        sparse: {
+            method(enabled) {
+
+                const value = enabled === undefined ? true : !!enabled;
+
+                if (this._flags.sparse === value) {
+                    return this;
+                }
+
+                const obj = value ? this.clone() : this.$_addRule('items');
+                return obj.$_setFlag('sparse', value, { clone: false });
+            }
+        },
+
+        unique: {
+            method(comparator, options = {}) {
+
+                Assert(!comparator || typeof comparator === 'function' || typeof comparator === 'string', 'comparator must be a function or a string');
+                Common.assertOptions(options, ['ignoreUndefined', 'separator']);
+
+                const rule = { name: 'unique', args: { options, comparator } };
+
+                if (comparator) {
+                    if (typeof comparator === 'string') {
+                        const separator = Common.default(options.separator, '.');
+                        rule.path = separator ? comparator.split(separator) : [comparator];
+                    }
+                    else {
+                        rule.comparator = comparator;
+                    }
+                }
+
+                return this.$_addRule(rule);
+            },
+            validate(value, { state, error, schema }, { comparator: raw, options }, { comparator, path }) {
+
+                const found = {
+                    string: Object.create(null),
+                    number: Object.create(null),
+                    undefined: Object.create(null),
+                    boolean: Object.create(null),
+                    object: new Map(),
+                    function: new Map(),
+                    custom: new Map()
+                };
+
+                const compare = comparator || DeepEqual;
+                const ignoreUndefined = options.ignoreUndefined;
+
+                for (let i = 0; i < value.length; ++i) {
+                    const item = path ? Reach(value[i], path) : value[i];
+                    const records = comparator ? found.custom : found[typeof item];
+                    Assert(records, 'Failed to find unique map container for type', typeof item);
+
+                    if (records instanceof Map) {
+                        const entries = records.entries();
+                        let current;
+                        while (!(current = entries.next()).done) {
+                            if (compare(current.value[0], item)) {
+                                const localState = state.localize([...state.path, i], [value, ...state.ancestors]);
+                                const context = {
+                                    pos: i,
+                                    value: value[i],
+                                    dupePos: current.value[1],
+                                    dupeValue: value[current.value[1]]
+                                };
+
+                                if (path) {
+                                    context.path = raw;
+                                }
+
+                                return error('array.unique', context, localState);
+                            }
+                        }
+
+                        records.set(item, i);
+                    }
+                    else {
+                        if ((!ignoreUndefined || item !== undefined) &&
+                            records[item] !== undefined) {
+
+                            const context = {
+                                pos: i,
+                                value: value[i],
+                                dupePos: records[item],
+                                dupeValue: value[records[item]]
+                            };
+
+                            if (path) {
+                                context.path = raw;
+                            }
+
+                            const localState = state.localize([...state.path, i], [value, ...state.ancestors]);
+                            return error('array.unique', context, localState);
+                        }
+
+                        records[item] = i;
+                    }
+                }
+
+                return value;
+            },
+            args: ['comparator', 'options'],
+            multi: true
+        }
+    },
+
+    cast: {
+        set: {
+            from: Array.isArray,
+            to(value, helpers) {
+
+                return new Set(value);
+            }
+        }
+    },
+
+    rebuild(schema) {
+
+        schema.$_terms._inclusions = [];
+        schema.$_terms._exclusions = [];
+        schema.$_terms._requireds = [];
+
+        for (const type of schema.$_terms.items) {
+            internals.validateSingle(type, schema);
+
+            if (type._flags.presence === 'required') {
+                schema.$_terms._requireds.push(type);
+            }
+            else if (type._flags.presence === 'forbidden') {
+                schema.$_terms._exclusions.push(type);
+            }
+            else {
+                schema.$_terms._inclusions.push(type);
+            }
+        }
+
+        for (const type of schema.$_terms.ordered) {
+            internals.validateSingle(type, schema);
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            if (desc.items) {
+                obj = obj.items(...desc.items);
+            }
+
+            if (desc.ordered) {
+                obj = obj.ordered(...desc.ordered);
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'array.base': '{{#label}} must be an array',
+        'array.excludes': '{{#label}} contains an excluded value',
+        'array.hasKnown': '{{#label}} does not contain at least one required match for type {:#patternLabel}',
+        'array.hasUnknown': '{{#label}} does not contain at least one required match',
+        'array.includes': '{{#label}} does not match any of the allowed types',
+        'array.includesRequiredBoth': '{{#label}} does not contain {{#knownMisses}} and {{#unknownMisses}} other required value(s)',
+        'array.includesRequiredKnowns': '{{#label}} does not contain {{#knownMisses}}',
+        'array.includesRequiredUnknowns': '{{#label}} does not contain {{#unknownMisses}} required value(s)',
+        'array.length': '{{#label}} must contain {{#limit}} items',
+        'array.max': '{{#label}} must contain less than or equal to {{#limit}} items',
+        'array.min': '{{#label}} must contain at least {{#limit}} items',
+        'array.orderedLength': '{{#label}} must contain at most {{#limit}} items',
+        'array.sort': '{{#label}} must be sorted in {#order} order by {{#by}}',
+        'array.sort.mismatching': '{{#label}} cannot be sorted due to mismatching types',
+        'array.sort.unsupported': '{{#label}} cannot be sorted due to unsupported type {#type}',
+        'array.sparse': '{{#label}} must not be a sparse array item',
+        'array.unique': '{{#label}} contains a duplicate value'
+    }
+});
+
+
+// Helpers
+
+internals.fillMissedErrors = function (schema, errors, requireds, value, state, prefs) {
+
+    const knownMisses = [];
+    let unknownMisses = 0;
+    for (const required of requireds) {
+        const label = required._flags.label;
+        if (label) {
+            knownMisses.push(label);
+        }
+        else {
+            ++unknownMisses;
+        }
+    }
+
+    if (knownMisses.length) {
+        if (unknownMisses) {
+            errors.push(schema.$_createError('array.includesRequiredBoth', value, { knownMisses, unknownMisses }, state, prefs));
+        }
+        else {
+            errors.push(schema.$_createError('array.includesRequiredKnowns', value, { knownMisses }, state, prefs));
+        }
+    }
+    else {
+        errors.push(schema.$_createError('array.includesRequiredUnknowns', value, { unknownMisses }, state, prefs));
+    }
+};
+
+
+internals.fillOrderedErrors = function (schema, errors, ordereds, value, state, prefs) {
+
+    const requiredOrdereds = [];
+
+    for (const ordered of ordereds) {
+        if (ordered._flags.presence === 'required') {
+            requiredOrdereds.push(ordered);
+        }
+    }
+
+    if (requiredOrdereds.length) {
+        internals.fillMissedErrors(schema, errors, requiredOrdereds, value, state, prefs);
+    }
+};
+
+
+internals.fastSplice = function (arr, i) {
+
+    let pos = i;
+    while (pos < arr.length) {
+        arr[pos++] = arr[pos];
+    }
+
+    --arr.length;
+};
+
+
+internals.validateSingle = function (type, obj) {
+
+    if (type.type === 'array' ||
+        type._flags._arrayItems) {
+
+        Assert(!obj._flags.single, 'Cannot specify array item with single rule enabled');
+        obj.$_setFlag('_arrayItems', true, { clone: false });
+    }
+};
+
+
+internals.sort = function (schema, value, settings, state, prefs) {
+
+    const order = settings.order === 'ascending' ? 1 : -1;
+    const aFirst = -1 * order;
+    const bFirst = order;
+
+    const sort = (a, b) => {
+
+        let compare = internals.compare(a, b, aFirst, bFirst);
+        if (compare !== null) {
+            return compare;
+        }
+
+        if (settings.by) {
+            a = settings.by.resolve(a, state, prefs);
+            b = settings.by.resolve(b, state, prefs);
+        }
+
+        compare = internals.compare(a, b, aFirst, bFirst);
+        if (compare !== null) {
+            return compare;
+        }
+
+        const type = typeof a;
+        if (type !== typeof b) {
+            throw schema.$_createError('array.sort.mismatching', value, null, state, prefs);
+        }
+
+        if (type !== 'number' &&
+            type !== 'string') {
+
+            throw schema.$_createError('array.sort.unsupported', value, { type }, state, prefs);
+        }
+
+        if (type === 'number') {
+            return (a - b) * order;
+        }
+
+        return a < b ? aFirst : bFirst;
+    };
+
+    try {
+        return { value: value.slice().sort(sort) };
+    }
+    catch (err) {
+        return { errors: err };
+    }
+};
+
+
+internals.compare = function (a, b, aFirst, bFirst) {
+
+    if (a === b) {
+        return 0;
+    }
+
+    if (a === undefined) {
+        return 1;           // Always last regardless of sort order
+    }
+
+    if (b === undefined) {
+        return -1;           // Always last regardless of sort order
+    }
+
+    if (a === null) {
+        return bFirst;
+    }
+
+    if (b === null) {
+        return aFirst;
+    }
+
+    return null;
+};
diff --git a/node_modules/joi/lib/types/binary.js b/node_modules/joi/lib/types/binary.js
new file mode 100644
index 00000000..9147166a
--- /dev/null
+++ b/node_modules/joi/lib/types/binary.js
@@ -0,0 +1,98 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+const Common = require('../common');
+
+
+const internals = {};
+
+
+module.exports = Any.extend({
+
+    type: 'binary',
+
+    coerce: {
+        from: 'string',
+        method(value, { schema }) {
+
+            try {
+                return { value: Buffer.from(value, schema._flags.encoding) };
+            }
+            catch (ignoreErr) { }
+        }
+    },
+
+    validate(value, { error }) {
+
+        if (!Buffer.isBuffer(value)) {
+            return { value, errors: error('binary.base') };
+        }
+    },
+
+    rules: {
+        encoding: {
+            method(encoding) {
+
+                Assert(Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
+
+                return this.$_setFlag('encoding', encoding);
+            }
+        },
+
+        length: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'length', method: 'length', args: { limit }, operator: '=' });
+            },
+            validate(value, helpers, { limit }, { name, operator, args }) {
+
+                if (Common.compare(value.length, limit, operator)) {
+                    return value;
+                }
+
+                return helpers.error('binary.' + name, { limit: args.limit, value });
+            },
+            args: [
+                {
+                    name: 'limit',
+                    ref: true,
+                    assert: Common.limit,
+                    message: 'must be a positive integer'
+                }
+            ]
+        },
+
+        max: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'max', method: 'length', args: { limit }, operator: '<=' });
+            }
+        },
+
+        min: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'min', method: 'length', args: { limit }, operator: '>=' });
+            }
+        }
+    },
+
+    cast: {
+        string: {
+            from: (value) => Buffer.isBuffer(value),
+            to(value, helpers) {
+
+                return value.toString();
+            }
+        }
+    },
+
+    messages: {
+        'binary.base': '{{#label}} must be a buffer or a string',
+        'binary.length': '{{#label}} must be {{#limit}} bytes',
+        'binary.max': '{{#label}} must be less than or equal to {{#limit}} bytes',
+        'binary.min': '{{#label}} must be at least {{#limit}} bytes'
+    }
+});
diff --git a/node_modules/joi/lib/types/boolean.js b/node_modules/joi/lib/types/boolean.js
new file mode 100644
index 00000000..68658664
--- /dev/null
+++ b/node_modules/joi/lib/types/boolean.js
@@ -0,0 +1,150 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+const Common = require('../common');
+const Values = require('../values');
+
+
+const internals = {};
+
+
+internals.isBool = function (value) {
+
+    return typeof value === 'boolean';
+};
+
+
+module.exports = Any.extend({
+
+    type: 'boolean',
+
+    flags: {
+
+        sensitive: { default: false }
+    },
+
+    terms: {
+
+        falsy: {
+            init: null,
+            manifest: 'values'
+        },
+
+        truthy: {
+            init: null,
+            manifest: 'values'
+        }
+    },
+
+    coerce(value, { schema }) {
+
+        if (typeof value === 'boolean') {
+            return;
+        }
+
+        if (typeof value === 'string') {
+            const normalized = schema._flags.sensitive ? value : value.toLowerCase();
+            value = normalized === 'true' ? true : (normalized === 'false' ? false : value);
+        }
+
+        if (typeof value !== 'boolean') {
+            value = schema.$_terms.truthy && schema.$_terms.truthy.has(value, null, null, !schema._flags.sensitive) ||
+                (schema.$_terms.falsy && schema.$_terms.falsy.has(value, null, null, !schema._flags.sensitive) ? false : value);
+        }
+
+        return { value };
+    },
+
+    validate(value, { error }) {
+
+        if (typeof value !== 'boolean') {
+            return { value, errors: error('boolean.base') };
+        }
+    },
+
+    rules: {
+        truthy: {
+            method(...values) {
+
+                Common.verifyFlat(values, 'truthy');
+
+                const obj = this.clone();
+                obj.$_terms.truthy = obj.$_terms.truthy || new Values();
+
+                for (let i = 0; i < values.length; ++i) {
+                    const value = values[i];
+
+                    Assert(value !== undefined, 'Cannot call truthy with undefined');
+                    obj.$_terms.truthy.add(value);
+                }
+
+                return obj;
+            }
+        },
+
+        falsy: {
+            method(...values) {
+
+                Common.verifyFlat(values, 'falsy');
+
+                const obj = this.clone();
+                obj.$_terms.falsy = obj.$_terms.falsy || new Values();
+
+                for (let i = 0; i < values.length; ++i) {
+                    const value = values[i];
+
+                    Assert(value !== undefined, 'Cannot call falsy with undefined');
+                    obj.$_terms.falsy.add(value);
+                }
+
+                return obj;
+            }
+        },
+
+        sensitive: {
+            method(enabled = true) {
+
+                return this.$_setFlag('sensitive', enabled);
+            }
+        }
+    },
+
+    cast: {
+        number: {
+            from: internals.isBool,
+            to(value, helpers) {
+
+                return value ? 1 : 0;
+            }
+        },
+        string: {
+            from: internals.isBool,
+            to(value, helpers) {
+
+                return value ? 'true' : 'false';
+            }
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            if (desc.truthy) {
+                obj = obj.truthy(...desc.truthy);
+            }
+
+            if (desc.falsy) {
+                obj = obj.falsy(...desc.falsy);
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'boolean.base': '{{#label}} must be a boolean'
+    }
+});
diff --git a/node_modules/joi/lib/types/date.js b/node_modules/joi/lib/types/date.js
new file mode 100644
index 00000000..b8206c6f
--- /dev/null
+++ b/node_modules/joi/lib/types/date.js
@@ -0,0 +1,233 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+const Common = require('../common');
+const Template = require('../template');
+
+
+const internals = {};
+
+
+internals.isDate = function (value) {
+
+    return value instanceof Date;
+};
+
+
+module.exports = Any.extend({
+
+    type: 'date',
+
+    coerce: {
+        from: ['number', 'string'],
+        method(value, { schema }) {
+
+            return { value: internals.parse(value, schema._flags.format) || value };
+        }
+    },
+
+    validate(value, { schema, error, prefs }) {
+
+        if (value instanceof Date &&
+            !isNaN(value.getTime())) {
+
+            return;
+        }
+
+        const format = schema._flags.format;
+
+        if (!prefs.convert ||
+            !format ||
+            typeof value !== 'string') {
+
+            return { value, errors: error('date.base') };
+        }
+
+        return { value, errors: error('date.format', { format }) };
+    },
+
+    rules: {
+
+        compare: {
+            method: false,
+            validate(value, helpers, { date }, { name, operator, args }) {
+
+                const to = date === 'now' ? Date.now() : date.getTime();
+                if (Common.compare(value.getTime(), to, operator)) {
+                    return value;
+                }
+
+                return helpers.error('date.' + name, { limit: args.date, value });
+            },
+            args: [
+                {
+                    name: 'date',
+                    ref: true,
+                    normalize: (date) => {
+
+                        return date === 'now' ? date : internals.parse(date);
+                    },
+                    assert: (date) => date !== null,
+                    message: 'must have a valid date format'
+                }
+            ]
+        },
+
+        format: {
+            method(format) {
+
+                Assert(['iso', 'javascript', 'unix'].includes(format), 'Unknown date format', format);
+
+                return this.$_setFlag('format', format);
+            }
+        },
+
+        greater: {
+            method(date) {
+
+                return this.$_addRule({ name: 'greater', method: 'compare', args: { date }, operator: '>' });
+            }
+        },
+
+        iso: {
+            method() {
+
+                return this.format('iso');
+            }
+        },
+
+        less: {
+            method(date) {
+
+                return this.$_addRule({ name: 'less', method: 'compare', args: { date }, operator: '<' });
+            }
+        },
+
+        max: {
+            method(date) {
+
+                return this.$_addRule({ name: 'max', method: 'compare', args: { date }, operator: '<=' });
+            }
+        },
+
+        min: {
+            method(date) {
+
+                return this.$_addRule({ name: 'min', method: 'compare', args: { date }, operator: '>=' });
+            }
+        },
+
+        timestamp: {
+            method(type = 'javascript') {
+
+                Assert(['javascript', 'unix'].includes(type), '"type" must be one of "javascript, unix"');
+
+                return this.format(type);
+            }
+        }
+    },
+
+    cast: {
+        number: {
+            from: internals.isDate,
+            to(value, helpers) {
+
+                return value.getTime();
+            }
+        },
+        string: {
+            from: internals.isDate,
+            to(value, { prefs }) {
+
+                return Template.date(value, prefs);
+            }
+        }
+    },
+
+    messages: {
+        'date.base': '{{#label}} must be a valid date',
+        'date.format': '{{#label}} must be in {msg("date.format." + #format) || #format} format',
+        'date.greater': '{{#label}} must be greater than {{:#limit}}',
+        'date.less': '{{#label}} must be less than {{:#limit}}',
+        'date.max': '{{#label}} must be less than or equal to {{:#limit}}',
+        'date.min': '{{#label}} must be greater than or equal to {{:#limit}}',
+
+        // Messages used in date.format
+
+        'date.format.iso': 'ISO 8601 date',
+        'date.format.javascript': 'timestamp or number of milliseconds',
+        'date.format.unix': 'timestamp or number of seconds'
+    }
+});
+
+
+// Helpers
+
+internals.parse = function (value, format) {
+
+    if (value instanceof Date) {
+        return value;
+    }
+
+    if (typeof value !== 'string' &&
+        (isNaN(value) || !isFinite(value))) {
+
+        return null;
+    }
+
+    if (/^\s*$/.test(value)) {
+        return null;
+    }
+
+    // ISO
+
+    if (format === 'iso') {
+        if (!Common.isIsoDate(value)) {
+            return null;
+        }
+
+        return internals.date(value.toString());
+    }
+
+    // Normalize number string
+
+    const original = value;
+    if (typeof value === 'string' &&
+        /^[+-]?\d+(\.\d+)?$/.test(value)) {
+
+        value = parseFloat(value);
+    }
+
+    // Timestamp
+
+    if (format) {
+        if (format === 'javascript') {
+            return internals.date(1 * value);        // Casting to number
+        }
+
+        if (format === 'unix') {
+            return internals.date(1000 * value);
+        }
+
+        if (typeof original === 'string') {
+            return null;
+        }
+    }
+
+    // Plain
+
+    return internals.date(value);
+};
+
+
+internals.date = function (value) {
+
+    const date = new Date(value);
+    if (!isNaN(date.getTime())) {
+        return date;
+    }
+
+    return null;
+};
diff --git a/node_modules/joi/lib/types/function.js b/node_modules/joi/lib/types/function.js
new file mode 100644
index 00000000..eb8792e4
--- /dev/null
+++ b/node_modules/joi/lib/types/function.js
@@ -0,0 +1,93 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Keys = require('./keys');
+
+
+const internals = {};
+
+
+module.exports = Keys.extend({
+
+    type: 'function',
+
+    properties: {
+        typeof: 'function'
+    },
+
+    rules: {
+        arity: {
+            method(n) {
+
+                Assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
+
+                return this.$_addRule({ name: 'arity', args: { n } });
+            },
+            validate(value, helpers, { n }) {
+
+                if (value.length === n) {
+                    return value;
+                }
+
+                return helpers.error('function.arity', { n });
+            }
+        },
+
+        class: {
+            method() {
+
+                return this.$_addRule('class');
+            },
+            validate(value, helpers) {
+
+                if ((/^\s*class\s/).test(value.toString())) {
+                    return value;
+                }
+
+                return helpers.error('function.class', { value });
+            }
+        },
+
+        minArity: {
+            method(n) {
+
+                Assert(Number.isSafeInteger(n) && n > 0, 'n must be a strict positive integer');
+
+                return this.$_addRule({ name: 'minArity', args: { n } });
+            },
+            validate(value, helpers, { n }) {
+
+                if (value.length >= n) {
+                    return value;
+                }
+
+                return helpers.error('function.minArity', { n });
+            }
+        },
+
+        maxArity: {
+            method(n) {
+
+                Assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
+
+                return this.$_addRule({ name: 'maxArity', args: { n } });
+            },
+            validate(value, helpers, { n }) {
+
+                if (value.length <= n) {
+                    return value;
+                }
+
+                return helpers.error('function.maxArity', { n });
+            }
+        }
+    },
+
+    messages: {
+        'function.arity': '{{#label}} must have an arity of {{#n}}',
+        'function.class': '{{#label}} must be a class',
+        'function.maxArity': '{{#label}} must have an arity lesser or equal to {{#n}}',
+        'function.minArity': '{{#label}} must have an arity greater or equal to {{#n}}'
+    }
+});
diff --git a/node_modules/joi/lib/types/keys.js b/node_modules/joi/lib/types/keys.js
new file mode 100644
index 00000000..678d660a
--- /dev/null
+++ b/node_modules/joi/lib/types/keys.js
@@ -0,0 +1,1043 @@
+'use strict';
+
+const ApplyToDefaults = require('@hapi/hoek/lib/applyToDefaults');
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+const Topo = require('@hapi/topo');
+
+const Any = require('./any');
+const Common = require('../common');
+const Compile = require('../compile');
+const Errors = require('../errors');
+const Ref = require('../ref');
+const Template = require('../template');
+
+
+const internals = {
+    renameDefaults: {
+        alias: false,                   // Keep old value in place
+        multiple: false,                // Allow renaming multiple keys into the same target
+        override: false                 // Overrides an existing key
+    }
+};
+
+
+module.exports = Any.extend({
+
+    type: '_keys',
+
+    properties: {
+
+        typeof: 'object'
+    },
+
+    flags: {
+
+        unknown: { default: false }
+    },
+
+    terms: {
+
+        dependencies: { init: null },
+        keys: { init: null, manifest: { mapped: { from: 'schema', to: 'key' } } },
+        patterns: { init: null },
+        renames: { init: null }
+    },
+
+    args(schema, keys) {
+
+        return schema.keys(keys);
+    },
+
+    validate(value, { schema, error, state, prefs }) {
+
+        if (!value ||
+            typeof value !== schema.$_property('typeof') ||
+            Array.isArray(value)) {
+
+            return { value, errors: error('object.base', { type: schema.$_property('typeof') }) };
+        }
+
+        // Skip if there are no other rules to test
+
+        if (!schema.$_terms.renames &&
+            !schema.$_terms.dependencies &&
+            !schema.$_terms.keys &&                       // null allows any keys
+            !schema.$_terms.patterns &&
+            !schema.$_terms.externals) {
+
+            return;
+        }
+
+        // Shallow clone value
+
+        value = internals.clone(value, prefs);
+        const errors = [];
+
+        // Rename keys
+
+        if (schema.$_terms.renames &&
+            !internals.rename(schema, value, state, prefs, errors)) {
+
+            return { value, errors };
+        }
+
+        // Anything allowed
+
+        if (!schema.$_terms.keys &&                       // null allows any keys
+            !schema.$_terms.patterns &&
+            !schema.$_terms.dependencies) {
+
+            return { value, errors };
+        }
+
+        // Defined keys
+
+        const unprocessed = new Set(Object.keys(value));
+
+        if (schema.$_terms.keys) {
+            const ancestors = [value, ...state.ancestors];
+
+            for (const child of schema.$_terms.keys) {
+                const key = child.key;
+                const item = value[key];
+
+                unprocessed.delete(key);
+
+                const localState = state.localize([...state.path, key], ancestors, child);
+                const result = child.schema.$_validate(item, localState, prefs);
+
+                if (result.errors) {
+                    if (prefs.abortEarly) {
+                        return { value, errors: result.errors };
+                    }
+
+                    errors.push(...result.errors);
+                }
+                else if (child.schema._flags.result === 'strip' ||
+                    result.value === undefined && item !== undefined) {
+
+                    delete value[key];
+                }
+                else if (result.value !== undefined) {
+                    value[key] = result.value;
+                }
+            }
+        }
+
+        // Unknown keys
+
+        if (unprocessed.size ||
+            schema._flags._hasPatternMatch) {
+
+            const early = internals.unknown(schema, value, unprocessed, errors, state, prefs);
+            if (early) {
+                return early;
+            }
+        }
+
+        // Validate dependencies
+
+        if (schema.$_terms.dependencies) {
+            for (const dep of schema.$_terms.dependencies) {
+                if (dep.key &&
+                    dep.key.resolve(value, state, prefs, null, { shadow: false }) === undefined) {
+
+                    continue;
+                }
+
+                const failed = internals.dependencies[dep.rel](schema, dep, value, state, prefs);
+                if (failed) {
+                    const report = schema.$_createError(failed.code, value, failed.context, state, prefs);
+                    if (prefs.abortEarly) {
+                        return { value, errors: report };
+                    }
+
+                    errors.push(report);
+                }
+            }
+        }
+
+        return { value, errors };
+    },
+
+    rules: {
+
+        and: {
+            method(...peers /*, [options] */) {
+
+                Common.verifyFlat(peers, 'and');
+
+                return internals.dependency(this, 'and', null, peers);
+            }
+        },
+
+        append: {
+            method(schema) {
+
+                if (schema === null ||
+                    schema === undefined ||
+                    Object.keys(schema).length === 0) {
+
+                    return this;
+                }
+
+                return this.keys(schema);
+            }
+        },
+
+        assert: {
+            method(subject, schema, message) {
+
+                if (!Template.isTemplate(subject)) {
+                    subject = Compile.ref(subject);
+                }
+
+                Assert(message === undefined || typeof message === 'string', 'Message must be a string');
+
+                schema = this.$_compile(schema, { appendPath: true });
+
+                const obj = this.$_addRule({ name: 'assert', args: { subject, schema, message } });
+                obj.$_mutateRegister(subject);
+                obj.$_mutateRegister(schema);
+                return obj;
+            },
+            validate(value, { error, prefs, state }, { subject, schema, message }) {
+
+                const about = subject.resolve(value, state, prefs);
+                const path = Ref.isRef(subject) ? subject.absolute(state) : [];
+                if (schema.$_match(about, state.localize(path, [value, ...state.ancestors], schema), prefs)) {
+                    return value;
+                }
+
+                return error('object.assert', { subject, message });
+            },
+            args: ['subject', 'schema', 'message'],
+            multi: true
+        },
+
+        instance: {
+            method(constructor, name) {
+
+                Assert(typeof constructor === 'function', 'constructor must be a function');
+
+                name = name || constructor.name;
+
+                return this.$_addRule({ name: 'instance', args: { constructor, name } });
+            },
+            validate(value, helpers, { constructor, name }) {
+
+                if (value instanceof constructor) {
+                    return value;
+                }
+
+                return helpers.error('object.instance', { type: name, value });
+            },
+            args: ['constructor', 'name']
+        },
+
+        keys: {
+            method(schema) {
+
+                Assert(schema === undefined || typeof schema === 'object', 'Object schema must be a valid object');
+                Assert(!Common.isSchema(schema), 'Object schema cannot be a joi schema');
+
+                const obj = this.clone();
+
+                if (!schema) {                                      // Allow all
+                    obj.$_terms.keys = null;
+                }
+                else if (!Object.keys(schema).length) {             // Allow none
+                    obj.$_terms.keys = new internals.Keys();
+                }
+                else {
+                    obj.$_terms.keys = obj.$_terms.keys ? obj.$_terms.keys.filter((child) => !schema.hasOwnProperty(child.key)) : new internals.Keys();
+                    for (const key in schema) {
+                        Common.tryWithPath(() => obj.$_terms.keys.push({ key, schema: this.$_compile(schema[key]) }), key);
+                    }
+                }
+
+                return obj.$_mutateRebuild();
+            }
+        },
+
+        length: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'length', args: { limit }, operator: '=' });
+            },
+            validate(value, helpers, { limit }, { name, operator, args }) {
+
+                if (Common.compare(Object.keys(value).length, limit, operator)) {
+                    return value;
+                }
+
+                return helpers.error('object.' + name, { limit: args.limit, value });
+            },
+            args: [
+                {
+                    name: 'limit',
+                    ref: true,
+                    assert: Common.limit,
+                    message: 'must be a positive integer'
+                }
+            ]
+        },
+
+        max: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'max', method: 'length', args: { limit }, operator: '<=' });
+            }
+        },
+
+        min: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'min', method: 'length', args: { limit }, operator: '>=' });
+            }
+        },
+
+        nand: {
+            method(...peers /*, [options] */) {
+
+                Common.verifyFlat(peers, 'nand');
+
+                return internals.dependency(this, 'nand', null, peers);
+            }
+        },
+
+        or: {
+            method(...peers /*, [options] */) {
+
+                Common.verifyFlat(peers, 'or');
+
+                return internals.dependency(this, 'or', null, peers);
+            }
+        },
+
+        oxor: {
+            method(...peers /*, [options] */) {
+
+                return internals.dependency(this, 'oxor', null, peers);
+            }
+        },
+
+        pattern: {
+            method(pattern, schema, options = {}) {
+
+                const isRegExp = pattern instanceof RegExp;
+                if (!isRegExp) {
+                    pattern = this.$_compile(pattern, { appendPath: true });
+                }
+
+                Assert(schema !== undefined, 'Invalid rule');
+                Common.assertOptions(options, ['fallthrough', 'matches']);
+
+                if (isRegExp) {
+                    Assert(!pattern.flags.includes('g') && !pattern.flags.includes('y'), 'pattern should not use global or sticky mode');
+                }
+
+                schema = this.$_compile(schema, { appendPath: true });
+
+                const obj = this.clone();
+                obj.$_terms.patterns = obj.$_terms.patterns || [];
+                const config = { [isRegExp ? 'regex' : 'schema']: pattern, rule: schema };
+                if (options.matches) {
+                    config.matches = this.$_compile(options.matches);
+                    if (config.matches.type !== 'array') {
+                        config.matches = config.matches.$_root.array().items(config.matches);
+                    }
+
+                    obj.$_mutateRegister(config.matches);
+                    obj.$_setFlag('_hasPatternMatch', true, { clone: false });
+                }
+
+                if (options.fallthrough) {
+                    config.fallthrough = true;
+                }
+
+                obj.$_terms.patterns.push(config);
+                obj.$_mutateRegister(schema);
+                return obj;
+            }
+        },
+
+        ref: {
+            method() {
+
+                return this.$_addRule('ref');
+            },
+            validate(value, helpers) {
+
+                if (Ref.isRef(value)) {
+                    return value;
+                }
+
+                return helpers.error('object.refType', { value });
+            }
+        },
+
+        regex: {
+            method() {
+
+                return this.$_addRule('regex');
+            },
+            validate(value, helpers) {
+
+                if (value instanceof RegExp) {
+                    return value;
+                }
+
+                return helpers.error('object.regex', { value });
+            }
+        },
+
+        rename: {
+            method(from, to, options = {}) {
+
+                Assert(typeof from === 'string' || from instanceof RegExp, 'Rename missing the from argument');
+                Assert(typeof to === 'string' || to instanceof Template, 'Invalid rename to argument');
+                Assert(to !== from, 'Cannot rename key to same name:', from);
+
+                Common.assertOptions(options, ['alias', 'ignoreUndefined', 'override', 'multiple']);
+
+                const obj = this.clone();
+
+                obj.$_terms.renames = obj.$_terms.renames || [];
+                for (const rename of obj.$_terms.renames) {
+                    Assert(rename.from !== from, 'Cannot rename the same key multiple times');
+                }
+
+                if (to instanceof Template) {
+                    obj.$_mutateRegister(to);
+                }
+
+                obj.$_terms.renames.push({
+                    from,
+                    to,
+                    options: ApplyToDefaults(internals.renameDefaults, options)
+                });
+
+                return obj;
+            }
+        },
+
+        schema: {
+            method(type = 'any') {
+
+                return this.$_addRule({ name: 'schema', args: { type } });
+            },
+            validate(value, helpers, { type }) {
+
+                if (Common.isSchema(value) &&
+                    (type === 'any' || value.type === type)) {
+
+                    return value;
+                }
+
+                return helpers.error('object.schema', { type });
+            }
+        },
+
+        unknown: {
+            method(allow) {
+
+                return this.$_setFlag('unknown', allow !== false);
+            }
+        },
+
+        with: {
+            method(key, peers, options = {}) {
+
+                return internals.dependency(this, 'with', key, peers, options);
+            }
+        },
+
+        without: {
+            method(key, peers, options = {}) {
+
+                return internals.dependency(this, 'without', key, peers, options);
+            }
+        },
+
+        xor: {
+            method(...peers /*, [options] */) {
+
+                Common.verifyFlat(peers, 'xor');
+
+                return internals.dependency(this, 'xor', null, peers);
+            }
+        }
+    },
+
+    overrides: {
+
+        default(value, options) {
+
+            if (value === undefined) {
+                value = Common.symbols.deepDefault;
+            }
+
+            return this.$_parent('default', value, options);
+        }
+    },
+
+    rebuild(schema) {
+
+        if (schema.$_terms.keys) {
+            const topo = new Topo.Sorter();
+            for (const child of schema.$_terms.keys) {
+                Common.tryWithPath(() => topo.add(child, { after: child.schema.$_rootReferences(), group: child.key }), child.key);
+            }
+
+            schema.$_terms.keys = new internals.Keys(...topo.nodes);
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            if (desc.keys) {
+                obj = obj.keys(desc.keys);
+            }
+
+            if (desc.dependencies) {
+                for (const { rel, key = null, peers, options } of desc.dependencies) {
+                    obj = internals.dependency(obj, rel, key, peers, options);
+                }
+            }
+
+            if (desc.patterns) {
+                for (const { regex, schema, rule, fallthrough, matches } of desc.patterns) {
+                    obj = obj.pattern(regex || schema, rule, { fallthrough, matches });
+                }
+            }
+
+            if (desc.renames) {
+                for (const { from, to, options } of desc.renames) {
+                    obj = obj.rename(from, to, options);
+                }
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'object.and': '{{#label}} contains {{#presentWithLabels}} without its required peers {{#missingWithLabels}}',
+        'object.assert': '{{#label}} is invalid because {if(#subject.key, `"` + #subject.key + `" failed to ` + (#message || "pass the assertion test"), #message || "the assertion failed")}',
+        'object.base': '{{#label}} must be of type {{#type}}',
+        'object.instance': '{{#label}} must be an instance of {{:#type}}',
+        'object.length': '{{#label}} must have {{#limit}} key{if(#limit == 1, "", "s")}',
+        'object.max': '{{#label}} must have less than or equal to {{#limit}} key{if(#limit == 1, "", "s")}',
+        'object.min': '{{#label}} must have at least {{#limit}} key{if(#limit == 1, "", "s")}',
+        'object.missing': '{{#label}} must contain at least one of {{#peersWithLabels}}',
+        'object.nand': '{{:#mainWithLabel}} must not exist simultaneously with {{#peersWithLabels}}',
+        'object.oxor': '{{#label}} contains a conflict between optional exclusive peers {{#peersWithLabels}}',
+        'object.pattern.match': '{{#label}} keys failed to match pattern requirements',
+        'object.refType': '{{#label}} must be a Joi reference',
+        'object.regex': '{{#label}} must be a RegExp object',
+        'object.rename.multiple': '{{#label}} cannot rename {{:#from}} because multiple renames are disabled and another key was already renamed to {{:#to}}',
+        'object.rename.override': '{{#label}} cannot rename {{:#from}} because override is disabled and target {{:#to}} exists',
+        'object.schema': '{{#label}} must be a Joi schema of {{#type}} type',
+        'object.unknown': '{{#label}} is not allowed',
+        'object.with': '{{:#mainWithLabel}} missing required peer {{:#peerWithLabel}}',
+        'object.without': '{{:#mainWithLabel}} conflict with forbidden peer {{:#peerWithLabel}}',
+        'object.xor': '{{#label}} contains a conflict between exclusive peers {{#peersWithLabels}}'
+    }
+});
+
+
+// Helpers
+
+internals.clone = function (value, prefs) {
+
+    // Object
+
+    if (typeof value === 'object') {
+        if (prefs.nonEnumerables) {
+            return Clone(value, { shallow: true });
+        }
+
+        const clone = Object.create(Object.getPrototypeOf(value));
+        Object.assign(clone, value);
+        return clone;
+    }
+
+    // Function
+
+    const clone = function (...args) {
+
+        return value.apply(this, args);
+    };
+
+    clone.prototype = Clone(value.prototype);
+    Object.defineProperty(clone, 'name', { value: value.name, writable: false });
+    Object.defineProperty(clone, 'length', { value: value.length, writable: false });
+    Object.assign(clone, value);
+    return clone;
+};
+
+
+internals.dependency = function (schema, rel, key, peers, options) {
+
+    Assert(key === null || typeof key === 'string', rel, 'key must be a strings');
+
+    // Extract options from peers array
+
+    if (!options) {
+        options = peers.length > 1 && typeof peers[peers.length - 1] === 'object' ? peers.pop() : {};
+    }
+
+    Common.assertOptions(options, ['separator']);
+
+    peers = [].concat(peers);
+
+    // Cast peer paths
+
+    const separator = Common.default(options.separator, '.');
+    const paths = [];
+    for (const peer of peers) {
+        Assert(typeof peer === 'string', rel, 'peers must be a string or a reference');
+        paths.push(Compile.ref(peer, { separator, ancestor: 0, prefix: false }));
+    }
+
+    // Cast key
+
+    if (key !== null) {
+        key = Compile.ref(key, { separator, ancestor: 0, prefix: false });
+    }
+
+    // Add rule
+
+    const obj = schema.clone();
+    obj.$_terms.dependencies = obj.$_terms.dependencies || [];
+    obj.$_terms.dependencies.push(new internals.Dependency(rel, key, paths, peers));
+    return obj;
+};
+
+
+internals.dependencies = {
+
+    and(schema, dep, value, state, prefs) {
+
+        const missing = [];
+        const present = [];
+        const count = dep.peers.length;
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) === undefined) {
+                missing.push(peer.key);
+            }
+            else {
+                present.push(peer.key);
+            }
+        }
+
+        if (missing.length !== count &&
+            present.length !== count) {
+
+            return {
+                code: 'object.and',
+                context: {
+                    present,
+                    presentWithLabels: internals.keysToLabels(schema, present),
+                    missing,
+                    missingWithLabels: internals.keysToLabels(schema, missing)
+                }
+            };
+        }
+    },
+
+    nand(schema, dep, value, state, prefs) {
+
+        const present = [];
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) !== undefined) {
+                present.push(peer.key);
+            }
+        }
+
+        if (present.length !== dep.peers.length) {
+            return;
+        }
+
+        const main = dep.paths[0];
+        const values = dep.paths.slice(1);
+        return {
+            code: 'object.nand',
+            context: {
+                main,
+                mainWithLabel: internals.keysToLabels(schema, main),
+                peers: values,
+                peersWithLabels: internals.keysToLabels(schema, values)
+            }
+        };
+    },
+
+    or(schema, dep, value, state, prefs) {
+
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) !== undefined) {
+                return;
+            }
+        }
+
+        return {
+            code: 'object.missing',
+            context: {
+                peers: dep.paths,
+                peersWithLabels: internals.keysToLabels(schema, dep.paths)
+            }
+        };
+    },
+
+    oxor(schema, dep, value, state, prefs) {
+
+        const present = [];
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) !== undefined) {
+                present.push(peer.key);
+            }
+        }
+
+        if (!present.length ||
+            present.length === 1) {
+
+            return;
+        }
+
+        const context = { peers: dep.paths, peersWithLabels: internals.keysToLabels(schema, dep.paths) };
+        context.present = present;
+        context.presentWithLabels = internals.keysToLabels(schema, present);
+        return { code: 'object.oxor', context };
+    },
+
+    with(schema, dep, value, state, prefs) {
+
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) === undefined) {
+                return {
+                    code: 'object.with',
+                    context: {
+                        main: dep.key.key,
+                        mainWithLabel: internals.keysToLabels(schema, dep.key.key),
+                        peer: peer.key,
+                        peerWithLabel: internals.keysToLabels(schema, peer.key)
+                    }
+                };
+            }
+        }
+    },
+
+    without(schema, dep, value, state, prefs) {
+
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) !== undefined) {
+                return {
+                    code: 'object.without',
+                    context: {
+                        main: dep.key.key,
+                        mainWithLabel: internals.keysToLabels(schema, dep.key.key),
+                        peer: peer.key,
+                        peerWithLabel: internals.keysToLabels(schema, peer.key)
+                    }
+                };
+            }
+        }
+    },
+
+    xor(schema, dep, value, state, prefs) {
+
+        const present = [];
+        for (const peer of dep.peers) {
+            if (peer.resolve(value, state, prefs, null, { shadow: false }) !== undefined) {
+                present.push(peer.key);
+            }
+        }
+
+        if (present.length === 1) {
+            return;
+        }
+
+        const context = { peers: dep.paths, peersWithLabels: internals.keysToLabels(schema, dep.paths) };
+        if (present.length === 0) {
+            return { code: 'object.missing', context };
+        }
+
+        context.present = present;
+        context.presentWithLabels = internals.keysToLabels(schema, present);
+        return { code: 'object.xor', context };
+    }
+};
+
+
+internals.keysToLabels = function (schema, keys) {
+
+    if (Array.isArray(keys)) {
+        return keys.map((key) => schema.$_mapLabels(key));
+    }
+
+    return schema.$_mapLabels(keys);
+};
+
+
+internals.rename = function (schema, value, state, prefs, errors) {
+
+    const renamed = {};
+    for (const rename of schema.$_terms.renames) {
+        const matches = [];
+        const pattern = typeof rename.from !== 'string';
+
+        if (!pattern) {
+            if (Object.prototype.hasOwnProperty.call(value, rename.from) &&
+                (value[rename.from] !== undefined || !rename.options.ignoreUndefined)) {
+
+                matches.push(rename);
+            }
+        }
+        else {
+            for (const from in value) {
+                if (value[from] === undefined &&
+                    rename.options.ignoreUndefined) {
+
+                    continue;
+                }
+
+                if (from === rename.to) {
+                    continue;
+                }
+
+                const match = rename.from.exec(from);
+                if (!match) {
+                    continue;
+                }
+
+                matches.push({ from, to: rename.to, match });
+            }
+        }
+
+        for (const match of matches) {
+            const from = match.from;
+            let to = match.to;
+            if (to instanceof Template) {
+                to = to.render(value, state, prefs, match.match);
+            }
+
+            if (from === to) {
+                continue;
+            }
+
+            if (!rename.options.multiple &&
+                renamed[to]) {
+
+                errors.push(schema.$_createError('object.rename.multiple', value, { from, to, pattern }, state, prefs));
+                if (prefs.abortEarly) {
+                    return false;
+                }
+            }
+
+            if (Object.prototype.hasOwnProperty.call(value, to) &&
+                !rename.options.override &&
+                !renamed[to]) {
+
+                errors.push(schema.$_createError('object.rename.override', value, { from, to, pattern }, state, prefs));
+                if (prefs.abortEarly) {
+                    return false;
+                }
+            }
+
+            if (value[from] === undefined) {
+                delete value[to];
+            }
+            else {
+                value[to] = value[from];
+            }
+
+            renamed[to] = true;
+
+            if (!rename.options.alias) {
+                delete value[from];
+            }
+        }
+    }
+
+    return true;
+};
+
+
+internals.unknown = function (schema, value, unprocessed, errors, state, prefs) {
+
+    if (schema.$_terms.patterns) {
+        let hasMatches = false;
+        const matches = schema.$_terms.patterns.map((pattern) => {
+
+            if (pattern.matches) {
+                hasMatches = true;
+                return [];
+            }
+        });
+
+        const ancestors = [value, ...state.ancestors];
+
+        for (const key of unprocessed) {
+            const item = value[key];
+            const path = [...state.path, key];
+
+            for (let i = 0; i < schema.$_terms.patterns.length; ++i) {
+                const pattern = schema.$_terms.patterns[i];
+                if (pattern.regex) {
+                    const match = pattern.regex.test(key);
+                    state.mainstay.tracer.debug(state, 'rule', `pattern.${i}`, match ? 'pass' : 'error');
+                    if (!match) {
+                        continue;
+                    }
+                }
+                else {
+                    if (!pattern.schema.$_match(key, state.nest(pattern.schema, `pattern.${i}`), prefs)) {
+                        continue;
+                    }
+                }
+
+                unprocessed.delete(key);
+
+                const localState = state.localize(path, ancestors, { schema: pattern.rule, key });
+                const result = pattern.rule.$_validate(item, localState, prefs);
+                if (result.errors) {
+                    if (prefs.abortEarly) {
+                        return { value, errors: result.errors };
+                    }
+
+                    errors.push(...result.errors);
+                }
+
+                if (pattern.matches) {
+                    matches[i].push(key);
+                }
+
+                value[key] = result.value;
+                if (!pattern.fallthrough) {
+                    break;
+                }
+            }
+        }
+
+        // Validate pattern matches rules
+
+        if (hasMatches) {
+            for (let i = 0; i < matches.length; ++i) {
+                const match = matches[i];
+                if (!match) {
+                    continue;
+                }
+
+                const stpm = schema.$_terms.patterns[i].matches;
+                const localState = state.localize(state.path, ancestors, stpm);
+                const result = stpm.$_validate(match, localState, prefs);
+                if (result.errors) {
+                    const details = Errors.details(result.errors, { override: false });
+                    details.matches = match;
+                    const report = schema.$_createError('object.pattern.match', value, details, state, prefs);
+                    if (prefs.abortEarly) {
+                        return { value, errors: report };
+                    }
+
+                    errors.push(report);
+                }
+            }
+        }
+    }
+
+    if (!unprocessed.size ||
+        !schema.$_terms.keys && !schema.$_terms.patterns) {     // If no keys or patterns specified, unknown keys allowed
+
+        return;
+    }
+
+    if (prefs.stripUnknown && !schema._flags.unknown ||
+        prefs.skipFunctions) {
+
+        const stripUnknown = prefs.stripUnknown ? (prefs.stripUnknown === true ? true : !!prefs.stripUnknown.objects) : false;
+
+        for (const key of unprocessed) {
+            if (stripUnknown) {
+                delete value[key];
+                unprocessed.delete(key);
+            }
+            else if (typeof value[key] === 'function') {
+                unprocessed.delete(key);
+            }
+        }
+    }
+
+    const forbidUnknown = !Common.default(schema._flags.unknown, prefs.allowUnknown);
+    if (forbidUnknown) {
+        for (const unprocessedKey of unprocessed) {
+            const localState = state.localize([...state.path, unprocessedKey], []);
+            const report = schema.$_createError('object.unknown', value[unprocessedKey], { child: unprocessedKey }, localState, prefs, { flags: false });
+            if (prefs.abortEarly) {
+                return { value, errors: report };
+            }
+
+            errors.push(report);
+        }
+    }
+};
+
+
+internals.Dependency = class {
+
+    constructor(rel, key, peers, paths) {
+
+        this.rel = rel;
+        this.key = key;
+        this.peers = peers;
+        this.paths = paths;
+    }
+
+    describe() {
+
+        const desc = {
+            rel: this.rel,
+            peers: this.paths
+        };
+
+        if (this.key !== null) {
+            desc.key = this.key.key;
+        }
+
+        if (this.peers[0].separator !== '.') {
+            desc.options = { separator: this.peers[0].separator };
+        }
+
+        return desc;
+    }
+};
+
+
+internals.Keys = class extends Array {
+
+    concat(source) {
+
+        const result = this.slice();
+
+        const keys = new Map();
+        for (let i = 0; i < result.length; ++i) {
+            keys.set(result[i].key, i);
+        }
+
+        for (const item of source) {
+            const key = item.key;
+            const pos = keys.get(key);
+            if (pos !== undefined) {
+                result[pos] = { key, schema: result[pos].schema.concat(item.schema) };
+            }
+            else {
+                result.push(item);
+            }
+        }
+
+        return result;
+    }
+};
diff --git a/node_modules/joi/lib/types/link.js b/node_modules/joi/lib/types/link.js
new file mode 100644
index 00000000..d99d0025
--- /dev/null
+++ b/node_modules/joi/lib/types/link.js
@@ -0,0 +1,168 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+const Common = require('../common');
+const Compile = require('../compile');
+const Errors = require('../errors');
+
+
+const internals = {};
+
+
+module.exports = Any.extend({
+
+    type: 'link',
+
+    properties: {
+        schemaChain: true
+    },
+
+    terms: {
+
+        link: { init: null, manifest: 'single', register: false }
+    },
+
+    args(schema, ref) {
+
+        return schema.ref(ref);
+    },
+
+    validate(value, { schema, state, prefs }) {
+
+        Assert(schema.$_terms.link, 'Uninitialized link schema');
+
+        const linked = internals.generate(schema, value, state, prefs);
+        const ref = schema.$_terms.link[0].ref;
+        return linked.$_validate(value, state.nest(linked, `link:${ref.display}:${linked.type}`), prefs);
+    },
+
+    generate(schema, value, state, prefs) {
+
+        return internals.generate(schema, value, state, prefs);
+    },
+
+    rules: {
+
+        ref: {
+            method(ref) {
+
+                Assert(!this.$_terms.link, 'Cannot reinitialize schema');
+
+                ref = Compile.ref(ref);
+
+                Assert(ref.type === 'value' || ref.type === 'local', 'Invalid reference type:', ref.type);
+                Assert(ref.type === 'local' || ref.ancestor === 'root' || ref.ancestor > 0, 'Link cannot reference itself');
+
+                const obj = this.clone();
+                obj.$_terms.link = [{ ref }];
+                return obj;
+            }
+        },
+
+        relative: {
+            method(enabled = true) {
+
+                return this.$_setFlag('relative', enabled);
+            }
+        }
+    },
+
+    overrides: {
+
+        concat(source) {
+
+            Assert(this.$_terms.link, 'Uninitialized link schema');
+            Assert(Common.isSchema(source), 'Invalid schema object');
+            Assert(source.type !== 'link', 'Cannot merge type link with another link');
+
+            const obj = this.clone();
+
+            if (!obj.$_terms.whens) {
+                obj.$_terms.whens = [];
+            }
+
+            obj.$_terms.whens.push({ concat: source });
+            return obj.$_mutateRebuild();
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            Assert(desc.link, 'Invalid link description missing link');
+            return obj.ref(desc.link);
+        }
+    }
+});
+
+
+// Helpers
+
+internals.generate = function (schema, value, state, prefs) {
+
+    let linked = state.mainstay.links.get(schema);
+    if (linked) {
+        return linked._generate(value, state, prefs).schema;
+    }
+
+    const ref = schema.$_terms.link[0].ref;
+    const { perspective, path } = internals.perspective(ref, state);
+    internals.assert(perspective, 'which is outside of schema boundaries', ref, schema, state, prefs);
+
+    try {
+        linked = path.length ? perspective.$_reach(path) : perspective;
+    }
+    catch (ignoreErr) {
+        internals.assert(false, 'to non-existing schema', ref, schema, state, prefs);
+    }
+
+    internals.assert(linked.type !== 'link', 'which is another link', ref, schema, state, prefs);
+
+    if (!schema._flags.relative) {
+        state.mainstay.links.set(schema, linked);
+    }
+
+    return linked._generate(value, state, prefs).schema;
+};
+
+
+internals.perspective = function (ref, state) {
+
+    if (ref.type === 'local') {
+        for (const { schema, key } of state.schemas) {                              // From parent to root
+            const id = schema._flags.id || key;
+            if (id === ref.path[0]) {
+                return { perspective: schema, path: ref.path.slice(1) };
+            }
+
+            if (schema.$_terms.shared) {
+                for (const shared of schema.$_terms.shared) {
+                    if (shared._flags.id === ref.path[0]) {
+                        return { perspective: shared, path: ref.path.slice(1) };
+                    }
+                }
+            }
+        }
+
+        return { perspective: null, path: null };
+    }
+
+    if (ref.ancestor === 'root') {
+        return { perspective: state.schemas[state.schemas.length - 1].schema, path: ref.path };
+    }
+
+    return { perspective: state.schemas[ref.ancestor] && state.schemas[ref.ancestor].schema, path: ref.path };
+};
+
+
+internals.assert = function (condition, message, ref, schema, state, prefs) {
+
+    if (condition) {                // Manual check to avoid generating error message on success
+        return;
+    }
+
+    Assert(false, `"${Errors.label(schema._flags, state, prefs)}" contains link reference "${ref.display}" ${message}`);
+};
diff --git a/node_modules/joi/lib/types/number.js b/node_modules/joi/lib/types/number.js
new file mode 100644
index 00000000..191db474
--- /dev/null
+++ b/node_modules/joi/lib/types/number.js
@@ -0,0 +1,335 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+const Common = require('../common');
+
+
+const internals = {
+    numberRx: /^\s*[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e([+-]?\d+))?\s*$/i,
+    precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/
+};
+
+
+module.exports = Any.extend({
+
+    type: 'number',
+
+    flags: {
+
+        unsafe: { default: false }
+    },
+
+    coerce: {
+        from: 'string',
+        method(value, { schema, error }) {
+
+            const matches = value.match(internals.numberRx);
+            if (!matches) {
+                return;
+            }
+
+            value = value.trim();
+            const result = { value: parseFloat(value) };
+
+            if (result.value === 0) {
+                result.value = 0;           // -0
+            }
+
+            if (!schema._flags.unsafe) {
+                if (value.match(/e/i)) {
+                    const constructed = internals.normalizeExponent(`${result.value / Math.pow(10, matches[1])}e${matches[1]}`);
+                    if (constructed !== internals.normalizeExponent(value)) {
+                        result.errors = error('number.unsafe');
+                        return result;
+                    }
+                }
+                else {
+                    const string = result.value.toString();
+                    if (string.match(/e/i)) {
+                        return result;
+                    }
+
+                    if (string !== internals.normalizeDecimal(value)) {
+                        result.errors = error('number.unsafe');
+                        return result;
+                    }
+                }
+            }
+
+            return result;
+        }
+    },
+
+    validate(value, { schema, error, prefs }) {
+
+        if (value === Infinity ||
+            value === -Infinity) {
+
+            return { value, errors: error('number.infinity') };
+        }
+
+        if (!Common.isNumber(value)) {
+            return { value, errors: error('number.base') };
+        }
+
+        const result = { value };
+
+        if (prefs.convert) {
+            const rule = schema.$_getRule('precision');
+            if (rule) {
+                const precision = Math.pow(10, rule.args.limit);                    // This is conceptually equivalent to using toFixed but it should be much faster
+                result.value = Math.round(result.value * precision) / precision;
+            }
+        }
+
+        if (result.value === 0) {
+            result.value = 0;           // -0
+        }
+
+        if (!schema._flags.unsafe &&
+            (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER)) {
+
+            result.errors = error('number.unsafe');
+        }
+
+        return result;
+    },
+
+    rules: {
+
+        compare: {
+            method: false,
+            validate(value, helpers, { limit }, { name, operator, args }) {
+
+                if (Common.compare(value, limit, operator)) {
+                    return value;
+                }
+
+                return helpers.error('number.' + name, { limit: args.limit, value });
+            },
+            args: [
+                {
+                    name: 'limit',
+                    ref: true,
+                    assert: Common.isNumber,
+                    message: 'must be a number'
+                }
+            ]
+        },
+
+        greater: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'greater', method: 'compare', args: { limit }, operator: '>' });
+            }
+        },
+
+        integer: {
+            method() {
+
+                return this.$_addRule('integer');
+            },
+            validate(value, helpers) {
+
+                if (Math.trunc(value) - value === 0) {
+                    return value;
+                }
+
+                return helpers.error('number.integer');
+            }
+        },
+
+        less: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'less', method: 'compare', args: { limit }, operator: '<' });
+            }
+        },
+
+        max: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'max', method: 'compare', args: { limit }, operator: '<=' });
+            }
+        },
+
+        min: {
+            method(limit) {
+
+                return this.$_addRule({ name: 'min', method: 'compare', args: { limit }, operator: '>=' });
+            }
+        },
+
+        multiple: {
+            method(base) {
+
+                return this.$_addRule({ name: 'multiple', args: { base } });
+            },
+            validate(value, helpers, { base }, options) {
+
+                if (value % base === 0) {
+                    return value;
+                }
+
+                return helpers.error('number.multiple', { multiple: options.args.base, value });
+            },
+            args: [
+                {
+                    name: 'base',
+                    ref: true,
+                    assert: (value) => typeof value === 'number' && isFinite(value) && value > 0,
+                    message: 'must be a positive number'
+                }
+            ],
+            multi: true
+        },
+
+        negative: {
+            method() {
+
+                return this.sign('negative');
+            }
+        },
+
+        port: {
+            method() {
+
+                return this.$_addRule('port');
+            },
+            validate(value, helpers) {
+
+                if (Number.isSafeInteger(value) &&
+                    value >= 0 &&
+                    value <= 65535) {
+
+                    return value;
+                }
+
+                return helpers.error('number.port');
+            }
+        },
+
+        positive: {
+            method() {
+
+                return this.sign('positive');
+            }
+        },
+
+        precision: {
+            method(limit) {
+
+                Assert(Number.isSafeInteger(limit), 'limit must be an integer');
+
+                return this.$_addRule({ name: 'precision', args: { limit } });
+            },
+            validate(value, helpers, { limit }) {
+
+                const places = value.toString().match(internals.precisionRx);
+                const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
+                if (decimals <= limit) {
+                    return value;
+                }
+
+                return helpers.error('number.precision', { limit, value });
+            },
+            convert: true
+        },
+
+        sign: {
+            method(sign) {
+
+                Assert(['negative', 'positive'].includes(sign), 'Invalid sign', sign);
+
+                return this.$_addRule({ name: 'sign', args: { sign } });
+            },
+            validate(value, helpers, { sign }) {
+
+                if (sign === 'negative' && value < 0 ||
+                    sign === 'positive' && value > 0) {
+
+                    return value;
+                }
+
+                return helpers.error(`number.${sign}`);
+            }
+        },
+
+        unsafe: {
+            method(enabled = true) {
+
+                Assert(typeof enabled === 'boolean', 'enabled must be a boolean');
+
+                return this.$_setFlag('unsafe', enabled);
+            }
+        }
+    },
+
+    cast: {
+        string: {
+            from: (value) => typeof value === 'number',
+            to(value, helpers) {
+
+                return value.toString();
+            }
+        }
+    },
+
+    messages: {
+        'number.base': '{{#label}} must be a number',
+        'number.greater': '{{#label}} must be greater than {{#limit}}',
+        'number.infinity': '{{#label}} cannot be infinity',
+        'number.integer': '{{#label}} must be an integer',
+        'number.less': '{{#label}} must be less than {{#limit}}',
+        'number.max': '{{#label}} must be less than or equal to {{#limit}}',
+        'number.min': '{{#label}} must be greater than or equal to {{#limit}}',
+        'number.multiple': '{{#label}} must be a multiple of {{#multiple}}',
+        'number.negative': '{{#label}} must be a negative number',
+        'number.port': '{{#label}} must be a valid port',
+        'number.positive': '{{#label}} must be a positive number',
+        'number.precision': '{{#label}} must have no more than {{#limit}} decimal places',
+        'number.unsafe': '{{#label}} must be a safe number'
+    }
+});
+
+
+// Helpers
+
+internals.normalizeExponent = function (str) {
+
+    return str
+        .replace(/E/, 'e')
+        .replace(/\.(\d*[1-9])?0+e/, '.$1e')
+        .replace(/\.e/, 'e')
+        .replace(/e\+/, 'e')
+        .replace(/^\+/, '')
+        .replace(/^(-?)0+([1-9])/, '$1$2');
+};
+
+
+internals.normalizeDecimal = function (str) {
+
+    str = str
+        // Remove leading plus signs
+        .replace(/^\+/, '')
+        // Remove trailing zeros if there is a decimal point and unecessary decimal points
+        .replace(/\.0*$/, '')
+        // Add a integer 0 if the numbers starts with a decimal point
+        .replace(/^(-?)\.([^\.]*)$/, '$10.$2')
+        // Remove leading zeros
+        .replace(/^(-?)0+([0-9])/, '$1$2');
+
+    if (str.includes('.') &&
+        str.endsWith('0')) {
+
+        str = str.replace(/0+$/, '');
+    }
+
+    if (str === '-0') {
+        return '0';
+    }
+
+    return str;
+};
diff --git a/node_modules/joi/lib/types/object.js b/node_modules/joi/lib/types/object.js
new file mode 100644
index 00000000..57046fdd
--- /dev/null
+++ b/node_modules/joi/lib/types/object.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const Keys = require('./keys');
+
+
+const internals = {};
+
+
+module.exports = Keys.extend({
+
+    type: 'object',
+
+    cast: {
+        map: {
+            from: (value) => value && typeof value === 'object',
+            to(value, helpers) {
+
+                return new Map(Object.entries(value));
+            }
+        }
+    }
+});
diff --git a/node_modules/joi/lib/types/string.js b/node_modules/joi/lib/types/string.js
new file mode 100644
index 00000000..103ce3c9
--- /dev/null
+++ b/node_modules/joi/lib/types/string.js
@@ -0,0 +1,820 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Domain = require('@sideway/address/lib/domain');
+const Email = require('@sideway/address/lib/email');
+const Ip = require('@sideway/address/lib/ip');
+const EscapeRegex = require('@hapi/hoek/lib/escapeRegex');
+const Tlds = require('@sideway/address/lib/tlds');
+const Uri = require('@sideway/address/lib/uri');
+
+const Any = require('./any');
+const Common = require('../common');
+
+
+const internals = {
+    tlds: Tlds instanceof Set ? { tlds: { allow: Tlds, deny: null } } : false,              // $lab:coverage:ignore$
+    base64Regex: {
+        // paddingRequired
+        true: {
+            // urlSafe
+            true: /^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}==|[\w\-]{3}=)?$/,
+            false: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
+        },
+        false: {
+            true: /^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}(==)?|[\w\-]{3}=?)?$/,
+            false: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/
+        }
+    },
+    dataUriRegex: /^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/,
+    hexRegex: /^[a-f0-9]+$/i,
+    ipRegex: Ip.regex().regex,
+    isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/,
+
+    guidBrackets: {
+        '{': '}', '[': ']', '(': ')', '': ''
+    },
+    guidVersions: {
+        uuidv1: '1',
+        uuidv2: '2',
+        uuidv3: '3',
+        uuidv4: '4',
+        uuidv5: '5'
+    },
+    guidSeparators: new Set([undefined, true, false, '-', ':']),
+
+    normalizationForms: ['NFC', 'NFD', 'NFKC', 'NFKD']
+};
+
+
+module.exports = Any.extend({
+
+    type: 'string',
+
+    flags: {
+
+        insensitive: { default: false },
+        truncate: { default: false }
+    },
+
+    terms: {
+
+        replacements: { init: null }
+    },
+
+    coerce: {
+        from: 'string',
+        method(value, { schema, state, prefs }) {
+
+            const normalize = schema.$_getRule('normalize');
+            if (normalize) {
+                value = value.normalize(normalize.args.form);
+            }
+
+            const casing = schema.$_getRule('case');
+            if (casing) {
+                value = casing.args.direction === 'upper' ? value.toLocaleUpperCase() : value.toLocaleLowerCase();
+            }
+
+            const trim = schema.$_getRule('trim');
+            if (trim &&
+                trim.args.enabled) {
+
+                value = value.trim();
+            }
+
+            if (schema.$_terms.replacements) {
+                for (const replacement of schema.$_terms.replacements) {
+                    value = value.replace(replacement.pattern, replacement.replacement);
+                }
+            }
+
+            const hex = schema.$_getRule('hex');
+            if (hex &&
+                hex.args.options.byteAligned &&
+                value.length % 2 !== 0) {
+
+                value = `0${value}`;
+            }
+
+            if (schema.$_getRule('isoDate')) {
+                const iso = internals.isoDate(value);
+                if (iso) {
+                    value = iso;
+                }
+            }
+
+            if (schema._flags.truncate) {
+                const rule = schema.$_getRule('max');
+                if (rule) {
+                    let limit = rule.args.limit;
+                    if (Common.isResolvable(limit)) {
+                        limit = limit.resolve(value, state, prefs);
+                        if (!Common.limit(limit)) {
+                            return { value, errors: schema.$_createError('any.ref', limit, { ref: rule.args.limit, arg: 'limit', reason: 'must be a positive integer' }, state, prefs) };
+                        }
+                    }
+
+                    value = value.slice(0, limit);
+                }
+            }
+
+            return { value };
+        }
+    },
+
+    validate(value, { error }) {
+
+        if (typeof value !== 'string') {
+            return { value, errors: error('string.base') };
+        }
+
+        if (value === '') {
+            return { value, errors: error('string.empty') };
+        }
+    },
+
+    rules: {
+
+        alphanum: {
+            method() {
+
+                return this.$_addRule('alphanum');
+            },
+            validate(value, helpers) {
+
+                if (/^[a-zA-Z0-9]+$/.test(value)) {
+                    return value;
+                }
+
+                return helpers.error('string.alphanum');
+            }
+        },
+
+        base64: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['paddingRequired', 'urlSafe']);
+
+                options = { urlSafe: false, paddingRequired: true, ...options };
+                Assert(typeof options.paddingRequired === 'boolean', 'paddingRequired must be boolean');
+                Assert(typeof options.urlSafe === 'boolean', 'urlSafe must be boolean');
+
+                return this.$_addRule({ name: 'base64', args: { options } });
+            },
+            validate(value, helpers, { options }) {
+
+                const regex = internals.base64Regex[options.paddingRequired][options.urlSafe];
+                if (regex.test(value)) {
+                    return value;
+                }
+
+                return helpers.error('string.base64');
+            }
+        },
+
+        case: {
+            method(direction) {
+
+                Assert(['lower', 'upper'].includes(direction), 'Invalid case:', direction);
+
+                return this.$_addRule({ name: 'case', args: { direction } });
+            },
+            validate(value, helpers, { direction }) {
+
+                if (direction === 'lower' && value === value.toLocaleLowerCase() ||
+                    direction === 'upper' && value === value.toLocaleUpperCase()) {
+
+                    return value;
+                }
+
+                return helpers.error(`string.${direction}case`);
+            },
+            convert: true
+        },
+
+        creditCard: {
+            method() {
+
+                return this.$_addRule('creditCard');
+            },
+            validate(value, helpers) {
+
+                let i = value.length;
+                let sum = 0;
+                let mul = 1;
+
+                while (i--) {
+                    const char = value.charAt(i) * mul;
+                    sum = sum + (char - (char > 9) * 9);
+                    mul = mul ^ 3;
+                }
+
+                if (sum > 0 &&
+                    sum % 10 === 0) {
+
+                    return value;
+                }
+
+                return helpers.error('string.creditCard');
+            }
+        },
+
+        dataUri: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['paddingRequired']);
+
+                options = { paddingRequired: true, ...options };
+                Assert(typeof options.paddingRequired === 'boolean', 'paddingRequired must be boolean');
+
+                return this.$_addRule({ name: 'dataUri', args: { options } });
+            },
+            validate(value, helpers, { options }) {
+
+                const matches = value.match(internals.dataUriRegex);
+
+                if (matches) {
+                    if (!matches[2]) {
+                        return value;
+                    }
+
+                    if (matches[2] !== 'base64') {
+                        return value;
+                    }
+
+                    const base64regex = internals.base64Regex[options.paddingRequired].false;
+                    if (base64regex.test(matches[3])) {
+                        return value;
+                    }
+                }
+
+                return helpers.error('string.dataUri');
+            }
+        },
+
+        domain: {
+            method(options) {
+
+                if (options) {
+                    Common.assertOptions(options, ['allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
+                }
+
+                const address = internals.addressOptions(options);
+                return this.$_addRule({ name: 'domain', args: { options }, address });
+            },
+            validate(value, helpers, args, { address }) {
+
+                if (Domain.isValid(value, address)) {
+                    return value;
+                }
+
+                return helpers.error('string.domain');
+            }
+        },
+
+        email: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['allowUnicode', 'ignoreLength', 'maxDomainSegments', 'minDomainSegments', 'multiple', 'separator', 'tlds']);
+                Assert(options.multiple === undefined || typeof options.multiple === 'boolean', 'multiple option must be an boolean');
+
+                const address = internals.addressOptions(options);
+                const regex = new RegExp(`\\s*[${options.separator ? EscapeRegex(options.separator) : ','}]\\s*`);
+
+                return this.$_addRule({ name: 'email', args: { options }, regex, address });
+            },
+            validate(value, helpers, { options }, { regex, address }) {
+
+                const emails = options.multiple ? value.split(regex) : [value];
+                const invalids = [];
+                for (const email of emails) {
+                    if (!Email.isValid(email, address)) {
+                        invalids.push(email);
+                    }
+                }
+
+                if (!invalids.length) {
+                    return value;
+                }
+
+                return helpers.error('string.email', { value, invalids });
+            }
+        },
+
+        guid: {
+            alias: 'uuid',
+            method(options = {}) {
+
+                Common.assertOptions(options, ['version', 'separator']);
+
+                let versionNumbers = '';
+
+                if (options.version) {
+                    const versions = [].concat(options.version);
+
+                    Assert(versions.length >= 1, 'version must have at least 1 valid version specified');
+                    const set = new Set();
+
+                    for (let i = 0; i < versions.length; ++i) {
+                        const version = versions[i];
+                        Assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
+                        const versionNumber = internals.guidVersions[version.toLowerCase()];
+                        Assert(versionNumber, 'version at position ' + i + ' must be one of ' + Object.keys(internals.guidVersions).join(', '));
+                        Assert(!set.has(versionNumber), 'version at position ' + i + ' must not be a duplicate');
+
+                        versionNumbers += versionNumber;
+                        set.add(versionNumber);
+                    }
+                }
+
+                Assert(internals.guidSeparators.has(options.separator), 'separator must be one of true, false, "-", or ":"');
+                const separator = options.separator === undefined ? '[:-]?' :
+                    options.separator === true ? '[:-]' :
+                        options.separator === false ? '[]?' : `\\${options.separator}`;
+
+                const regex = new RegExp(`^([\\[{\\(]?)[0-9A-F]{8}(${separator})[0-9A-F]{4}\\2?[${versionNumbers || '0-9A-F'}][0-9A-F]{3}\\2?[${versionNumbers ? '89AB' : '0-9A-F'}][0-9A-F]{3}\\2?[0-9A-F]{12}([\\]}\\)]?)$`, 'i');
+
+                return this.$_addRule({ name: 'guid', args: { options }, regex });
+            },
+            validate(value, helpers, args, { regex }) {
+
+                const results = regex.exec(value);
+
+                if (!results) {
+                    return helpers.error('string.guid');
+                }
+
+                // Matching braces
+
+                if (internals.guidBrackets[results[1]] !== results[results.length - 1]) {
+                    return helpers.error('string.guid');
+                }
+
+                return value;
+            }
+        },
+
+        hex: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['byteAligned']);
+
+                options = { byteAligned: false, ...options };
+                Assert(typeof options.byteAligned === 'boolean', 'byteAligned must be boolean');
+
+                return this.$_addRule({ name: 'hex', args: { options } });
+            },
+            validate(value, helpers, { options }) {
+
+                if (!internals.hexRegex.test(value)) {
+                    return helpers.error('string.hex');
+                }
+
+                if (options.byteAligned &&
+                    value.length % 2 !== 0) {
+
+                    return helpers.error('string.hexAlign');
+                }
+
+                return value;
+            }
+        },
+
+        hostname: {
+            method() {
+
+                return this.$_addRule('hostname');
+            },
+            validate(value, helpers) {
+
+                if (Domain.isValid(value, { minDomainSegments: 1 }) ||
+                    internals.ipRegex.test(value)) {
+
+                    return value;
+                }
+
+                return helpers.error('string.hostname');
+            }
+        },
+
+        insensitive: {
+            method() {
+
+                return this.$_setFlag('insensitive', true);
+            }
+        },
+
+        ip: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['cidr', 'version']);
+
+                const { cidr, versions, regex } = Ip.regex(options);
+                const version = options.version ? versions : undefined;
+                return this.$_addRule({ name: 'ip', args: { options: { cidr, version } }, regex });
+            },
+            validate(value, helpers, { options }, { regex }) {
+
+                if (regex.test(value)) {
+                    return value;
+                }
+
+                if (options.version) {
+                    return helpers.error('string.ipVersion', { value, cidr: options.cidr, version: options.version });
+                }
+
+                return helpers.error('string.ip', { value, cidr: options.cidr });
+            }
+        },
+
+        isoDate: {
+            method() {
+
+                return this.$_addRule('isoDate');
+            },
+            validate(value, { error }) {
+
+                if (internals.isoDate(value)) {
+                    return value;
+                }
+
+                return error('string.isoDate');
+            }
+        },
+
+        isoDuration: {
+            method() {
+
+                return this.$_addRule('isoDuration');
+            },
+            validate(value, helpers) {
+
+                if (internals.isoDurationRegex.test(value)) {
+                    return value;
+                }
+
+                return helpers.error('string.isoDuration');
+            }
+        },
+
+        length: {
+            method(limit, encoding) {
+
+                return internals.length(this, 'length', limit, '=', encoding);
+            },
+            validate(value, helpers, { limit, encoding }, { name, operator, args }) {
+
+                const length = encoding ? Buffer && Buffer.byteLength(value, encoding) : value.length;      // $lab:coverage:ignore$
+                if (Common.compare(length, limit, operator)) {
+                    return value;
+                }
+
+                return helpers.error('string.' + name, { limit: args.limit, value, encoding });
+            },
+            args: [
+                {
+                    name: 'limit',
+                    ref: true,
+                    assert: Common.limit,
+                    message: 'must be a positive integer'
+                },
+                'encoding'
+            ]
+        },
+
+        lowercase: {
+            method() {
+
+                return this.case('lower');
+            }
+        },
+
+        max: {
+            method(limit, encoding) {
+
+                return internals.length(this, 'max', limit, '<=', encoding);
+            },
+            args: ['limit', 'encoding']
+        },
+
+        min: {
+            method(limit, encoding) {
+
+                return internals.length(this, 'min', limit, '>=', encoding);
+            },
+            args: ['limit', 'encoding']
+        },
+
+        normalize: {
+            method(form = 'NFC') {
+
+                Assert(internals.normalizationForms.includes(form), 'normalization form must be one of ' + internals.normalizationForms.join(', '));
+
+                return this.$_addRule({ name: 'normalize', args: { form } });
+            },
+            validate(value, { error }, { form }) {
+
+                if (value === value.normalize(form)) {
+                    return value;
+                }
+
+                return error('string.normalize', { value, form });
+            },
+            convert: true
+        },
+
+        pattern: {
+            alias: 'regex',
+            method(regex, options = {}) {
+
+                Assert(regex instanceof RegExp, 'regex must be a RegExp');
+                Assert(!regex.flags.includes('g') && !regex.flags.includes('y'), 'regex should not use global or sticky mode');
+
+                if (typeof options === 'string') {
+                    options = { name: options };
+                }
+
+                Common.assertOptions(options, ['invert', 'name']);
+
+                const errorCode = ['string.pattern', options.invert ? '.invert' : '', options.name ? '.name' : '.base'].join('');
+                return this.$_addRule({ name: 'pattern', args: { regex, options }, errorCode });
+            },
+            validate(value, helpers, { regex, options }, { errorCode }) {
+
+                const patternMatch = regex.test(value);
+
+                if (patternMatch ^ options.invert) {
+                    return value;
+                }
+
+                return helpers.error(errorCode, { name: options.name, regex, value });
+            },
+            args: ['regex', 'options'],
+            multi: true
+        },
+
+        replace: {
+            method(pattern, replacement) {
+
+                if (typeof pattern === 'string') {
+                    pattern = new RegExp(EscapeRegex(pattern), 'g');
+                }
+
+                Assert(pattern instanceof RegExp, 'pattern must be a RegExp');
+                Assert(typeof replacement === 'string', 'replacement must be a String');
+
+                const obj = this.clone();
+
+                if (!obj.$_terms.replacements) {
+                    obj.$_terms.replacements = [];
+                }
+
+                obj.$_terms.replacements.push({ pattern, replacement });
+                return obj;
+            }
+        },
+
+        token: {
+            method() {
+
+                return this.$_addRule('token');
+            },
+            validate(value, helpers) {
+
+                if (/^\w+$/.test(value)) {
+                    return value;
+                }
+
+                return helpers.error('string.token');
+            }
+        },
+
+        trim: {
+            method(enabled = true) {
+
+                Assert(typeof enabled === 'boolean', 'enabled must be a boolean');
+
+                return this.$_addRule({ name: 'trim', args: { enabled } });
+            },
+            validate(value, helpers, { enabled }) {
+
+                if (!enabled ||
+                    value === value.trim()) {
+
+                    return value;
+                }
+
+                return helpers.error('string.trim');
+            },
+            convert: true
+        },
+
+        truncate: {
+            method(enabled = true) {
+
+                Assert(typeof enabled === 'boolean', 'enabled must be a boolean');
+
+                return this.$_setFlag('truncate', enabled);
+            }
+        },
+
+        uppercase: {
+            method() {
+
+                return this.case('upper');
+            }
+        },
+
+        uri: {
+            method(options = {}) {
+
+                Common.assertOptions(options, ['allowRelative', 'allowQuerySquareBrackets', 'domain', 'relativeOnly', 'scheme']);
+
+                if (options.domain) {
+                    Common.assertOptions(options.domain, ['allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
+                }
+
+                const { regex, scheme } = Uri.regex(options);
+                const domain = options.domain ? internals.addressOptions(options.domain) : null;
+                return this.$_addRule({ name: 'uri', args: { options }, regex, domain, scheme });
+            },
+            validate(value, helpers, { options }, { regex, domain, scheme }) {
+
+                if (['http:/', 'https:/'].includes(value)) {            // scheme:/ is technically valid but makes no sense
+                    return helpers.error('string.uri');
+                }
+
+                const match = regex.exec(value);
+                if (match) {
+                    if (domain) {
+                        const matched = match[1] || match[2];
+                        if (!Domain.isValid(matched, domain)) {
+                            return helpers.error('string.domain', { value: matched });
+                        }
+                    }
+
+                    return value;
+                }
+
+                if (options.relativeOnly) {
+                    return helpers.error('string.uriRelativeOnly');
+                }
+
+                if (options.scheme) {
+                    return helpers.error('string.uriCustomScheme', { scheme, value });
+                }
+
+                return helpers.error('string.uri');
+            }
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            if (desc.replacements) {
+                for (const { pattern, replacement } of desc.replacements) {
+                    obj = obj.replace(pattern, replacement);
+                }
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'string.alphanum': '{{#label}} must only contain alpha-numeric characters',
+        'string.base': '{{#label}} must be a string',
+        'string.base64': '{{#label}} must be a valid base64 string',
+        'string.creditCard': '{{#label}} must be a credit card',
+        'string.dataUri': '{{#label}} must be a valid dataUri string',
+        'string.domain': '{{#label}} must contain a valid domain name',
+        'string.email': '{{#label}} must be a valid email',
+        'string.empty': '{{#label}} is not allowed to be empty',
+        'string.guid': '{{#label}} must be a valid GUID',
+        'string.hex': '{{#label}} must only contain hexadecimal characters',
+        'string.hexAlign': '{{#label}} hex decoded representation must be byte aligned',
+        'string.hostname': '{{#label}} must be a valid hostname',
+        'string.ip': '{{#label}} must be a valid ip address with a {{#cidr}} CIDR',
+        'string.ipVersion': '{{#label}} must be a valid ip address of one of the following versions {{#version}} with a {{#cidr}} CIDR',
+        'string.isoDate': '{{#label}} must be in iso format',
+        'string.isoDuration': '{{#label}} must be a valid ISO 8601 duration',
+        'string.length': '{{#label}} length must be {{#limit}} characters long',
+        'string.lowercase': '{{#label}} must only contain lowercase characters',
+        'string.max': '{{#label}} length must be less than or equal to {{#limit}} characters long',
+        'string.min': '{{#label}} length must be at least {{#limit}} characters long',
+        'string.normalize': '{{#label}} must be unicode normalized in the {{#form}} form',
+        'string.token': '{{#label}} must only contain alpha-numeric and underscore characters',
+        'string.pattern.base': '{{#label}} with value {:[.]} fails to match the required pattern: {{#regex}}',
+        'string.pattern.name': '{{#label}} with value {:[.]} fails to match the {{#name}} pattern',
+        'string.pattern.invert.base': '{{#label}} with value {:[.]} matches the inverted pattern: {{#regex}}',
+        'string.pattern.invert.name': '{{#label}} with value {:[.]} matches the inverted {{#name}} pattern',
+        'string.trim': '{{#label}} must not have leading or trailing whitespace',
+        'string.uri': '{{#label}} must be a valid uri',
+        'string.uriCustomScheme': '{{#label}} must be a valid uri with a scheme matching the {{#scheme}} pattern',
+        'string.uriRelativeOnly': '{{#label}} must be a valid relative uri',
+        'string.uppercase': '{{#label}} must only contain uppercase characters'
+    }
+});
+
+
+// Helpers
+
+internals.addressOptions = function (options) {
+
+    if (!options) {
+        return options;
+    }
+
+    // minDomainSegments
+
+    Assert(options.minDomainSegments === undefined ||
+        Number.isSafeInteger(options.minDomainSegments) && options.minDomainSegments > 0, 'minDomainSegments must be a positive integer');
+
+    // maxDomainSegments
+
+    Assert(options.maxDomainSegments === undefined ||
+        Number.isSafeInteger(options.maxDomainSegments) && options.maxDomainSegments > 0, 'maxDomainSegments must be a positive integer');
+
+    // tlds
+
+    if (options.tlds === false) {
+        return options;
+    }
+
+    if (options.tlds === true ||
+        options.tlds === undefined) {
+
+        Assert(internals.tlds, 'Built-in TLD list disabled');
+        return Object.assign({}, options, internals.tlds);
+    }
+
+    Assert(typeof options.tlds === 'object', 'tlds must be true, false, or an object');
+
+    const deny = options.tlds.deny;
+    if (deny) {
+        if (Array.isArray(deny)) {
+            options = Object.assign({}, options, { tlds: { deny: new Set(deny) } });
+        }
+
+        Assert(options.tlds.deny instanceof Set, 'tlds.deny must be an array, Set, or boolean');
+        Assert(!options.tlds.allow, 'Cannot specify both tlds.allow and tlds.deny lists');
+        internals.validateTlds(options.tlds.deny, 'tlds.deny');
+        return options;
+    }
+
+    const allow = options.tlds.allow;
+    if (!allow) {
+        return options;
+    }
+
+    if (allow === true) {
+        Assert(internals.tlds, 'Built-in TLD list disabled');
+        return Object.assign({}, options, internals.tlds);
+    }
+
+    if (Array.isArray(allow)) {
+        options = Object.assign({}, options, { tlds: { allow: new Set(allow) } });
+    }
+
+    Assert(options.tlds.allow instanceof Set, 'tlds.allow must be an array, Set, or boolean');
+    internals.validateTlds(options.tlds.allow, 'tlds.allow');
+    return options;
+};
+
+
+internals.validateTlds = function (set, source) {
+
+    for (const tld of set) {
+        Assert(Domain.isValid(tld, { minDomainSegments: 1, maxDomainSegments: 1 }), `${source} must contain valid top level domain names`);
+    }
+};
+
+
+internals.isoDate = function (value) {
+
+    if (!Common.isIsoDate(value)) {
+        return null;
+    }
+
+    if (/.*T.*[+-]\d\d$/.test(value)) {             // Add missing trailing zeros to timeshift
+        value += '00';
+    }
+
+    const date = new Date(value);
+    if (isNaN(date.getTime())) {
+        return null;
+    }
+
+    return date.toISOString();
+};
+
+
+internals.length = function (schema, name, limit, operator, encoding) {
+
+    Assert(!encoding || Buffer && Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);      // $lab:coverage:ignore$
+
+    return schema.$_addRule({ name, method: 'length', args: { limit, encoding }, operator });
+};
diff --git a/node_modules/joi/lib/types/symbol.js b/node_modules/joi/lib/types/symbol.js
new file mode 100644
index 00000000..eafe9ae5
--- /dev/null
+++ b/node_modules/joi/lib/types/symbol.js
@@ -0,0 +1,102 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+
+const Any = require('./any');
+
+
+const internals = {};
+
+
+internals.Map = class extends Map {
+
+    slice() {
+
+        return new internals.Map(this);
+    }
+};
+
+
+module.exports = Any.extend({
+
+    type: 'symbol',
+
+    terms: {
+
+        map: { init: new internals.Map() }
+    },
+
+    coerce: {
+        method(value, { schema, error }) {
+
+            const lookup = schema.$_terms.map.get(value);
+            if (lookup) {
+                value = lookup;
+            }
+
+            if (!schema._flags.only ||
+                typeof value === 'symbol') {
+
+                return { value };
+            }
+
+            return { value, errors: error('symbol.map', { map: schema.$_terms.map }) };
+        }
+    },
+
+    validate(value, { error }) {
+
+        if (typeof value !== 'symbol') {
+            return { value, errors: error('symbol.base') };
+        }
+    },
+
+    rules: {
+        map: {
+            method(iterable) {
+
+                if (iterable &&
+                    !iterable[Symbol.iterator] &&
+                    typeof iterable === 'object') {
+
+                    iterable = Object.entries(iterable);
+                }
+
+                Assert(iterable && iterable[Symbol.iterator], 'Iterable must be an iterable or object');
+
+                const obj = this.clone();
+
+                const symbols = [];
+                for (const entry of iterable) {
+                    Assert(entry && entry[Symbol.iterator], 'Entry must be an iterable');
+                    const [key, value] = entry;
+
+                    Assert(typeof key !== 'object' && typeof key !== 'function' && typeof key !== 'symbol', 'Key must not be of type object, function, or Symbol');
+                    Assert(typeof value === 'symbol', 'Value must be a Symbol');
+
+                    obj.$_terms.map.set(key, value);
+                    symbols.push(value);
+                }
+
+                return obj.valid(...symbols);
+            }
+        }
+    },
+
+    manifest: {
+
+        build(obj, desc) {
+
+            if (desc.map) {
+                obj = obj.map(desc.map);
+            }
+
+            return obj;
+        }
+    },
+
+    messages: {
+        'symbol.base': '{{#label}} must be a symbol',
+        'symbol.map': '{{#label}} must be one of {{#map}}'
+    }
+});
diff --git a/node_modules/joi/lib/validator.js b/node_modules/joi/lib/validator.js
new file mode 100644
index 00000000..c7fe231e
--- /dev/null
+++ b/node_modules/joi/lib/validator.js
@@ -0,0 +1,650 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const Clone = require('@hapi/hoek/lib/clone');
+const Ignore = require('@hapi/hoek/lib/ignore');
+const Reach = require('@hapi/hoek/lib/reach');
+
+const Common = require('./common');
+const Errors = require('./errors');
+const State = require('./state');
+
+
+const internals = {
+    result: Symbol('result')
+};
+
+
+exports.entry = function (value, schema, prefs) {
+
+    let settings = Common.defaults;
+    if (prefs) {
+        Assert(prefs.warnings === undefined, 'Cannot override warnings preference in synchronous validation');
+        Assert(prefs.artifacts === undefined, 'Cannot override artifacts preference in synchronous validation');
+        settings = Common.preferences(Common.defaults, prefs);
+    }
+
+    const result = internals.entry(value, schema, settings);
+    Assert(!result.mainstay.externals.length, 'Schema with external rules must use validateAsync()');
+    const outcome = { value: result.value };
+
+    if (result.error) {
+        outcome.error = result.error;
+    }
+
+    if (result.mainstay.warnings.length) {
+        outcome.warning = Errors.details(result.mainstay.warnings);
+    }
+
+    if (result.mainstay.debug) {
+        outcome.debug = result.mainstay.debug;
+    }
+
+    if (result.mainstay.artifacts) {
+        outcome.artifacts = result.mainstay.artifacts;
+    }
+
+    return outcome;
+};
+
+
+exports.entryAsync = async function (value, schema, prefs) {
+
+    let settings = Common.defaults;
+    if (prefs) {
+        settings = Common.preferences(Common.defaults, prefs);
+    }
+
+    const result = internals.entry(value, schema, settings);
+    const mainstay = result.mainstay;
+    if (result.error) {
+        if (mainstay.debug) {
+            result.error.debug = mainstay.debug;
+        }
+
+        throw result.error;
+    }
+
+    if (mainstay.externals.length) {
+        let root = result.value;
+        for (const { method, path, label } of mainstay.externals) {
+            let node = root;
+            let key;
+            let parent;
+
+            if (path.length) {
+                key = path[path.length - 1];
+                parent = Reach(root, path.slice(0, -1));
+                node = parent[key];
+            }
+
+            try {
+                const output = await method(node, { prefs });
+                if (output === undefined ||
+                    output === node) {
+
+                    continue;
+                }
+
+                if (parent) {
+                    parent[key] = output;
+                }
+                else {
+                    root = output;
+                }
+            }
+            catch (err) {
+                err.message += ` (${label})`;       // Change message to include path
+                throw err;
+            }
+        }
+
+        result.value = root;
+    }
+
+    if (!settings.warnings &&
+        !settings.debug &&
+        !settings.artifacts) {
+
+        return result.value;
+    }
+
+    const outcome = { value: result.value };
+    if (mainstay.warnings.length) {
+        outcome.warning = Errors.details(mainstay.warnings);
+    }
+
+    if (mainstay.debug) {
+        outcome.debug = mainstay.debug;
+    }
+
+    if (mainstay.artifacts) {
+        outcome.artifacts = mainstay.artifacts;
+    }
+
+    return outcome;
+};
+
+
+internals.entry = function (value, schema, prefs) {
+
+    // Prepare state
+
+    const { tracer, cleanup } = internals.tracer(schema, prefs);
+    const debug = prefs.debug ? [] : null;
+    const links = schema._ids._schemaChain ? new Map() : null;
+    const mainstay = { externals: [], warnings: [], tracer, debug, links };
+    const schemas = schema._ids._schemaChain ? [{ schema }] : null;
+    const state = new State([], [], { mainstay, schemas });
+
+    // Validate value
+
+    const result = exports.validate(value, schema, state, prefs);
+
+    // Process value and errors
+
+    if (cleanup) {
+        schema.$_root.untrace();
+    }
+
+    const error = Errors.process(result.errors, value, prefs);
+    return { value: result.value, error, mainstay };
+};
+
+
+internals.tracer = function (schema, prefs) {
+
+    if (schema.$_root._tracer) {
+        return { tracer: schema.$_root._tracer._register(schema) };
+    }
+
+    if (prefs.debug) {
+        Assert(schema.$_root.trace, 'Debug mode not supported');
+        return { tracer: schema.$_root.trace()._register(schema), cleanup: true };
+    }
+
+    return { tracer: internals.ignore };
+};
+
+
+exports.validate = function (value, schema, state, prefs, overrides = {}) {
+
+    if (schema.$_terms.whens) {
+        schema = schema._generate(value, state, prefs).schema;
+    }
+
+    // Setup state and settings
+
+    if (schema._preferences) {
+        prefs = internals.prefs(schema, prefs);
+    }
+
+    // Cache
+
+    if (schema._cache &&
+        prefs.cache) {
+
+        const result = schema._cache.get(value);
+        state.mainstay.tracer.debug(state, 'validate', 'cached', !!result);
+        if (result) {
+            return result;
+        }
+    }
+
+    // Helpers
+
+    const createError = (code, local, localState) => schema.$_createError(code, value, local, localState || state, prefs);
+    const helpers = {
+        original: value,
+        prefs,
+        schema,
+        state,
+        error: createError,
+        errorsArray: internals.errorsArray,
+        warn: (code, local, localState) => state.mainstay.warnings.push(createError(code, local, localState)),
+        message: (messages, local) => schema.$_createError('custom', value, local, state, prefs, { messages })
+    };
+
+    // Prepare
+
+    state.mainstay.tracer.entry(schema, state);
+
+    const def = schema._definition;
+    if (def.prepare &&
+        value !== undefined &&
+        prefs.convert) {
+
+        const prepared = def.prepare(value, helpers);
+        if (prepared) {
+            state.mainstay.tracer.value(state, 'prepare', value, prepared.value);
+            if (prepared.errors) {
+                return internals.finalize(prepared.value, [].concat(prepared.errors), helpers);         // Prepare error always aborts early
+            }
+
+            value = prepared.value;
+        }
+    }
+
+    // Type coercion
+
+    if (def.coerce &&
+        value !== undefined &&
+        prefs.convert &&
+        (!def.coerce.from || def.coerce.from.includes(typeof value))) {
+
+        const coerced = def.coerce.method(value, helpers);
+        if (coerced) {
+            state.mainstay.tracer.value(state, 'coerced', value, coerced.value);
+            if (coerced.errors) {
+                return internals.finalize(coerced.value, [].concat(coerced.errors), helpers);           // Coerce error always aborts early
+            }
+
+            value = coerced.value;
+        }
+    }
+
+    // Empty value
+
+    const empty = schema._flags.empty;
+    if (empty &&
+        empty.$_match(internals.trim(value, schema), state.nest(empty), Common.defaults)) {
+
+        state.mainstay.tracer.value(state, 'empty', value, undefined);
+        value = undefined;
+    }
+
+    // Presence requirements (required, optional, forbidden)
+
+    const presence = overrides.presence || schema._flags.presence || (schema._flags._endedSwitch ? null : prefs.presence);
+    if (value === undefined) {
+        if (presence === 'forbidden') {
+            return internals.finalize(value, null, helpers);
+        }
+
+        if (presence === 'required') {
+            return internals.finalize(value, [schema.$_createError('any.required', value, null, state, prefs)], helpers);
+        }
+
+        if (presence === 'optional') {
+            if (schema._flags.default !== Common.symbols.deepDefault) {
+                return internals.finalize(value, null, helpers);
+            }
+
+            state.mainstay.tracer.value(state, 'default', value, {});
+            value = {};
+        }
+    }
+    else if (presence === 'forbidden') {
+        return internals.finalize(value, [schema.$_createError('any.unknown', value, null, state, prefs)], helpers);
+    }
+
+    // Allowed values
+
+    const errors = [];
+
+    if (schema._valids) {
+        const match = schema._valids.get(value, state, prefs, schema._flags.insensitive);
+        if (match) {
+            if (prefs.convert) {
+                state.mainstay.tracer.value(state, 'valids', value, match.value);
+                value = match.value;
+            }
+
+            state.mainstay.tracer.filter(schema, state, 'valid', match);
+            return internals.finalize(value, null, helpers);
+        }
+
+        if (schema._flags.only) {
+            const report = schema.$_createError('any.only', value, { valids: schema._valids.values({ display: true }) }, state, prefs);
+            if (prefs.abortEarly) {
+                return internals.finalize(value, [report], helpers);
+            }
+
+            errors.push(report);
+        }
+    }
+
+    // Denied values
+
+    if (schema._invalids) {
+        const match = schema._invalids.get(value, state, prefs, schema._flags.insensitive);
+        if (match) {
+            state.mainstay.tracer.filter(schema, state, 'invalid', match);
+            const report = schema.$_createError('any.invalid', value, { invalids: schema._invalids.values({ display: true }) }, state, prefs);
+            if (prefs.abortEarly) {
+                return internals.finalize(value, [report], helpers);
+            }
+
+            errors.push(report);
+        }
+    }
+
+    // Base type
+
+    if (def.validate) {
+        const base = def.validate(value, helpers);
+        if (base) {
+            state.mainstay.tracer.value(state, 'base', value, base.value);
+            value = base.value;
+
+            if (base.errors) {
+                if (!Array.isArray(base.errors)) {
+                    errors.push(base.errors);
+                    return internals.finalize(value, errors, helpers);          // Base error always aborts early
+                }
+
+                if (base.errors.length) {
+                    errors.push(...base.errors);
+                    return internals.finalize(value, errors, helpers);          // Base error always aborts early
+                }
+            }
+        }
+    }
+
+    // Validate tests
+
+    if (!schema._rules.length) {
+        return internals.finalize(value, errors, helpers);
+    }
+
+    return internals.rules(value, errors, helpers);
+};
+
+
+internals.rules = function (value, errors, helpers) {
+
+    const { schema, state, prefs } = helpers;
+
+    for (const rule of schema._rules) {
+        const definition = schema._definition.rules[rule.method];
+
+        // Skip rules that are also applied in coerce step
+
+        if (definition.convert &&
+            prefs.convert) {
+
+            state.mainstay.tracer.log(schema, state, 'rule', rule.name, 'full');
+            continue;
+        }
+
+        // Resolve references
+
+        let ret;
+        let args = rule.args;
+        if (rule._resolve.length) {
+            args = Object.assign({}, args);                                     // Shallow copy
+            for (const key of rule._resolve) {
+                const resolver = definition.argsByName.get(key);
+
+                const resolved = args[key].resolve(value, state, prefs);
+                const normalized = resolver.normalize ? resolver.normalize(resolved) : resolved;
+
+                const invalid = Common.validateArg(normalized, null, resolver);
+                if (invalid) {
+                    ret = schema.$_createError('any.ref', resolved, { arg: key, ref: args[key], reason: invalid }, state, prefs);
+                    break;
+                }
+
+                args[key] = normalized;
+            }
+        }
+
+        // Test rule
+
+        ret = ret || definition.validate(value, helpers, args, rule);           // Use ret if already set to reference error
+
+        const result = internals.rule(ret, rule);
+        if (result.errors) {
+            state.mainstay.tracer.log(schema, state, 'rule', rule.name, 'error');
+
+            if (rule.warn) {
+                state.mainstay.warnings.push(...result.errors);
+                continue;
+            }
+
+            if (prefs.abortEarly) {
+                return internals.finalize(value, result.errors, helpers);
+            }
+
+            errors.push(...result.errors);
+        }
+        else {
+            state.mainstay.tracer.log(schema, state, 'rule', rule.name, 'pass');
+            state.mainstay.tracer.value(state, 'rule', value, result.value, rule.name);
+            value = result.value;
+        }
+    }
+
+    return internals.finalize(value, errors, helpers);
+};
+
+
+internals.rule = function (ret, rule) {
+
+    if (ret instanceof Errors.Report) {
+        internals.error(ret, rule);
+        return { errors: [ret], value: null };
+    }
+
+    if (Array.isArray(ret) &&
+        ret[Common.symbols.errors]) {
+
+        ret.forEach((report) => internals.error(report, rule));
+        return { errors: ret, value: null };
+    }
+
+    return { errors: null, value: ret };
+};
+
+
+internals.error = function (report, rule) {
+
+    if (rule.message) {
+        report._setTemplate(rule.message);
+    }
+
+    return report;
+};
+
+
+internals.finalize = function (value, errors, helpers) {
+
+    errors = errors || [];
+    const { schema, state, prefs } = helpers;
+
+    // Failover value
+
+    if (errors.length) {
+        const failover = internals.default('failover', undefined, errors, helpers);
+        if (failover !== undefined) {
+            state.mainstay.tracer.value(state, 'failover', value, failover);
+            value = failover;
+            errors = [];
+        }
+    }
+
+    // Error override
+
+    if (errors.length &&
+        schema._flags.error) {
+
+        if (typeof schema._flags.error === 'function') {
+            errors = schema._flags.error(errors);
+            if (!Array.isArray(errors)) {
+                errors = [errors];
+            }
+
+            for (const error of errors) {
+                Assert(error instanceof Error || error instanceof Errors.Report, 'error() must return an Error object');
+            }
+        }
+        else {
+            errors = [schema._flags.error];
+        }
+    }
+
+    // Default
+
+    if (value === undefined) {
+        const defaulted = internals.default('default', value, errors, helpers);
+        state.mainstay.tracer.value(state, 'default', value, defaulted);
+        value = defaulted;
+    }
+
+    // Cast
+
+    if (schema._flags.cast &&
+        value !== undefined) {
+
+        const caster = schema._definition.cast[schema._flags.cast];
+        if (caster.from(value)) {
+            const casted = caster.to(value, helpers);
+            state.mainstay.tracer.value(state, 'cast', value, casted, schema._flags.cast);
+            value = casted;
+        }
+    }
+
+    // Externals
+
+    if (schema.$_terms.externals &&
+        prefs.externals &&
+        prefs._externals !== false) {                       // Disabled for matching
+
+        for (const { method } of schema.$_terms.externals) {
+            state.mainstay.externals.push({ method, path: state.path, label: Errors.label(schema._flags, state, prefs) });
+        }
+    }
+
+    // Result
+
+    const result = { value, errors: errors.length ? errors : null };
+
+    if (schema._flags.result) {
+        result.value = schema._flags.result === 'strip' ? undefined : /* raw */ helpers.original;
+        state.mainstay.tracer.value(state, schema._flags.result, value, result.value);
+        state.shadow(value, schema._flags.result);
+    }
+
+    // Cache
+
+    if (schema._cache &&
+        prefs.cache !== false &&
+        !schema._refs.length) {
+
+        schema._cache.set(helpers.original, result);
+    }
+
+    // Artifacts
+
+    if (value !== undefined &&
+        !result.errors &&
+        schema._flags.artifact !== undefined) {
+
+        state.mainstay.artifacts = state.mainstay.artifacts || new Map();
+        if (!state.mainstay.artifacts.has(schema._flags.artifact)) {
+            state.mainstay.artifacts.set(schema._flags.artifact, []);
+        }
+
+        state.mainstay.artifacts.get(schema._flags.artifact).push(state.path);
+    }
+
+    return result;
+};
+
+
+internals.prefs = function (schema, prefs) {
+
+    const isDefaultOptions = prefs === Common.defaults;
+    if (isDefaultOptions &&
+        schema._preferences[Common.symbols.prefs]) {
+
+        return schema._preferences[Common.symbols.prefs];
+    }
+
+    prefs = Common.preferences(prefs, schema._preferences);
+    if (isDefaultOptions) {
+        schema._preferences[Common.symbols.prefs] = prefs;
+    }
+
+    return prefs;
+};
+
+
+internals.default = function (flag, value, errors, helpers) {
+
+    const { schema, state, prefs } = helpers;
+    const source = schema._flags[flag];
+    if (prefs.noDefaults ||
+        source === undefined) {
+
+        return value;
+    }
+
+    state.mainstay.tracer.log(schema, state, 'rule', flag, 'full');
+
+    if (!source) {
+        return source;
+    }
+
+    if (typeof source === 'function') {
+        const args = source.length ? [Clone(state.ancestors[0]), helpers] : [];
+
+        try {
+            return source(...args);
+        }
+        catch (err) {
+            errors.push(schema.$_createError(`any.${flag}`, null, { error: err }, state, prefs));
+            return;
+        }
+    }
+
+    if (typeof source !== 'object') {
+        return source;
+    }
+
+    if (source[Common.symbols.literal]) {
+        return source.literal;
+    }
+
+    if (Common.isResolvable(source)) {
+        return source.resolve(value, state, prefs);
+    }
+
+    return Clone(source);
+};
+
+
+internals.trim = function (value, schema) {
+
+    if (typeof value !== 'string') {
+        return value;
+    }
+
+    const trim = schema.$_getRule('trim');
+    if (!trim ||
+        !trim.args.enabled) {
+
+        return value;
+    }
+
+    return value.trim();
+};
+
+
+internals.ignore = {
+    active: false,
+    debug: Ignore,
+    entry: Ignore,
+    filter: Ignore,
+    log: Ignore,
+    resolve: Ignore,
+    value: Ignore
+};
+
+
+internals.errorsArray = function () {
+
+    const errors = [];
+    errors[Common.symbols.errors] = true;
+    return errors;
+};
diff --git a/node_modules/joi/lib/values.js b/node_modules/joi/lib/values.js
new file mode 100644
index 00000000..bfdb90b4
--- /dev/null
+++ b/node_modules/joi/lib/values.js
@@ -0,0 +1,263 @@
+'use strict';
+
+const Assert = require('@hapi/hoek/lib/assert');
+const DeepEqual = require('@hapi/hoek/lib/deepEqual');
+
+const Common = require('./common');
+
+
+const internals = {};
+
+
+module.exports = internals.Values = class {
+
+    constructor(values, refs) {
+
+        this._values = new Set(values);
+        this._refs = new Set(refs);
+        this._lowercase = internals.lowercases(values);
+
+        this._override = false;
+    }
+
+    get length() {
+
+        return this._values.size + this._refs.size;
+    }
+
+    add(value, refs) {
+
+        // Reference
+
+        if (Common.isResolvable(value)) {
+            if (!this._refs.has(value)) {
+                this._refs.add(value);
+
+                if (refs) {                     // Skipped in a merge
+                    refs.register(value);
+                }
+            }
+
+            return;
+        }
+
+        // Value
+
+        if (!this.has(value, null, null, false)) {
+            this._values.add(value);
+
+            if (typeof value === 'string') {
+                this._lowercase.set(value.toLowerCase(), value);
+            }
+        }
+    }
+
+    static merge(target, source, remove) {
+
+        target = target || new internals.Values();
+
+        if (source) {
+            if (source._override) {
+                return source.clone();
+            }
+
+            for (const item of [...source._values, ...source._refs]) {
+                target.add(item);
+            }
+        }
+
+        if (remove) {
+            for (const item of [...remove._values, ...remove._refs]) {
+                target.remove(item);
+            }
+        }
+
+        return target.length ? target : null;
+    }
+
+    remove(value) {
+
+        // Reference
+
+        if (Common.isResolvable(value)) {
+            this._refs.delete(value);
+            return;
+        }
+
+        // Value
+
+        this._values.delete(value);
+
+        if (typeof value === 'string') {
+            this._lowercase.delete(value.toLowerCase());
+        }
+    }
+
+    has(value, state, prefs, insensitive) {
+
+        return !!this.get(value, state, prefs, insensitive);
+    }
+
+    get(value, state, prefs, insensitive) {
+
+        if (!this.length) {
+            return false;
+        }
+
+        // Simple match
+
+        if (this._values.has(value)) {
+            return { value };
+        }
+
+        // Case insensitive string match
+
+        if (typeof value === 'string' &&
+            value &&
+            insensitive) {
+
+            const found = this._lowercase.get(value.toLowerCase());
+            if (found) {
+                return { value: found };
+            }
+        }
+
+        if (!this._refs.size &&
+            typeof value !== 'object') {
+
+            return false;
+        }
+
+        // Objects
+
+        if (typeof value === 'object') {
+            for (const item of this._values) {
+                if (DeepEqual(item, value)) {
+                    return { value: item };
+                }
+            }
+        }
+
+        // References
+
+        if (state) {
+            for (const ref of this._refs) {
+                const resolved = ref.resolve(value, state, prefs, null, { in: true });
+                if (resolved === undefined) {
+                    continue;
+                }
+
+                const items = !ref.in || typeof resolved !== 'object'
+                    ? [resolved]
+                    : Array.isArray(resolved) ? resolved : Object.keys(resolved);
+
+                for (const item of items) {
+                    if (typeof item !== typeof value) {
+                        continue;
+                    }
+
+                    if (insensitive &&
+                        value &&
+                        typeof value === 'string') {
+
+                        if (item.toLowerCase() === value.toLowerCase()) {
+                            return { value: item, ref };
+                        }
+                    }
+                    else {
+                        if (DeepEqual(item, value)) {
+                            return { value: item, ref };
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    override() {
+
+        this._override = true;
+    }
+
+    values(options) {
+
+        if (options &&
+            options.display) {
+
+            const values = [];
+
+            for (const item of [...this._values, ...this._refs]) {
+                if (item !== undefined) {
+                    values.push(item);
+                }
+            }
+
+            return values;
+        }
+
+        return Array.from([...this._values, ...this._refs]);
+    }
+
+    clone() {
+
+        const set = new internals.Values(this._values, this._refs);
+        set._override = this._override;
+        return set;
+    }
+
+    concat(source) {
+
+        Assert(!source._override, 'Cannot concat override set of values');
+
+        const set = new internals.Values([...this._values, ...source._values], [...this._refs, ...source._refs]);
+        set._override = this._override;
+        return set;
+    }
+
+    describe() {
+
+        const normalized = [];
+
+        if (this._override) {
+            normalized.push({ override: true });
+        }
+
+        for (const value of this._values.values()) {
+            normalized.push(value && typeof value === 'object' ? { value } : value);
+        }
+
+        for (const value of this._refs.values()) {
+            normalized.push(value.describe());
+        }
+
+        return normalized;
+    }
+};
+
+
+internals.Values.prototype[Common.symbols.values] = true;
+
+
+// Aliases
+
+internals.Values.prototype.slice = internals.Values.prototype.clone;
+
+
+// Helpers
+
+internals.lowercases = function (from) {
+
+    const map = new Map();
+
+    if (from) {
+        for (const value of from) {
+            if (typeof value === 'string') {
+                map.set(value.toLowerCase(), value);
+            }
+        }
+    }
+
+    return map;
+};
diff --git a/node_modules/joi/package.json b/node_modules/joi/package.json
new file mode 100644
index 00000000..155df806
--- /dev/null
+++ b/node_modules/joi/package.json
@@ -0,0 +1,70 @@
+{
+  "_from": "joi",
+  "_id": "joi@17.3.0",
+  "_inBundle": false,
+  "_integrity": "sha512-Qh5gdU6niuYbUIUV5ejbsMiiFmBdw8Kcp8Buj2JntszCkCfxJ9Cz76OtHxOZMPXrt5810iDIXs+n1nNVoquHgg==",
+  "_location": "/joi",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "joi",
+    "name": "joi",
+    "escapedName": "joi",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/joi/-/joi-17.3.0.tgz",
+  "_shasum": "f1be4a6ce29bc1716665819ac361dfa139fff5d2",
+  "_spec": "joi",
+  "_where": "C:\\Users\\V S THARUNIKA\\Documents\\book-racker",
+  "browser": "dist/joi-browser.min.js",
+  "bugs": {
+    "url": "https://github.com/sideway/joi/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "@hapi/hoek": "^9.0.0",
+    "@hapi/topo": "^5.0.0",
+    "@sideway/address": "^4.1.0",
+    "@sideway/formula": "^3.0.0",
+    "@sideway/pinpoint": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "Object schema validation",
+  "devDependencies": {
+    "@hapi/bourne": "2.x.x",
+    "@hapi/code": "8.x.x",
+    "@hapi/joi-legacy-test": "npm:@hapi/joi@15.x.x",
+    "@hapi/lab": "24.x.x",
+    "typescript": "4.0.x"
+  },
+  "files": [
+    "lib/**/*",
+    "dist/*"
+  ],
+  "homepage": "https://github.com/sideway/joi#readme",
+  "keywords": [
+    "schema",
+    "validation"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "joi",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/sideway/joi.git"
+  },
+  "scripts": {
+    "prepublishOnly": "cd browser && npm install && npm run build",
+    "test": "lab -t 100 -a @hapi/code -L -Y",
+    "test-cov-html": "lab -r html -o coverage.html -a @hapi/code"
+  },
+  "types": "lib/index.d.ts",
+  "version": "17.3.0"
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..b17647da
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,49 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "@hapi/hoek": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.1.0.tgz",
+      "integrity": "sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw=="
+    },
+    "@hapi/topo": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz",
+      "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==",
+      "requires": {
+        "@hapi/hoek": "^9.0.0"
+      }
+    },
+    "@sideway/address": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.0.tgz",
+      "integrity": "sha512-wAH/JYRXeIFQRsxerIuLjgUu2Xszam+O5xKeatJ4oudShOOirfmsQ1D6LL54XOU2tizpCYku+s1wmU0SYdpoSA==",
+      "requires": {
+        "@hapi/hoek": "^9.0.0"
+      }
+    },
+    "@sideway/formula": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
+      "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
+    },
+    "@sideway/pinpoint": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
+      "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="
+    },
+    "joi": {
+      "version": "17.3.0",
+      "resolved": "https://registry.npmjs.org/joi/-/joi-17.3.0.tgz",
+      "integrity": "sha512-Qh5gdU6niuYbUIUV5ejbsMiiFmBdw8Kcp8Buj2JntszCkCfxJ9Cz76OtHxOZMPXrt5810iDIXs+n1nNVoquHgg==",
+      "requires": {
+        "@hapi/hoek": "^9.0.0",
+        "@hapi/topo": "^5.0.0",
+        "@sideway/address": "^4.1.0",
+        "@sideway/formula": "^3.0.0",
+        "@sideway/pinpoint": "^2.0.0"
+      }
+    }
+  }
+}
-- 
GitLab