speckoloo
Version:
Domain entites inspired by Speck
278 lines (184 loc) • 35.1 kB
JavaScript
'use strict';
var _ava = require('ava');
var _buildSchema = require('./build-schema');
var _buildSchema2 = _interopRequireDefault(_buildSchema);
var _defaultValidators = require('./default-validators');
var _common = require('./common');
var _buildSchema3 = require('./build-schema.fixture');
var fixtures = _interopRequireWildcard(_buildSchema3);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
(0, _ava.test)('[Structure] Given schema definition, when final schema is built, then it should have created the default schema', t => {
var _fixtures$schemaWitho = fixtures.schemaWithoutCustomValidators,
_fixtures$schemaWitho2 = _fixtures$schemaWitho.$contexts;
const $contexts = _fixtures$schemaWitho2 === undefined ? {} : _fixtures$schemaWitho2,
definition = _objectWithoutProperties(_fixtures$schemaWitho, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.truthy(result.default);
});
(0, _ava.test)('[Structure] Given schema definition with no contexts, when final schema is built, then it should be no extra keys in it', t => {
const expectedKeys = ['default'];
var _fixtures$schemaWitho3 = fixtures.schemaWithoutCustomValidators,
_fixtures$schemaWitho4 = _fixtures$schemaWitho3.$contexts;
const $contexts = _fixtures$schemaWitho4 === undefined ? {} : _fixtures$schemaWitho4,
definition = _objectWithoutProperties(_fixtures$schemaWitho3, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(Object.keys(result), expectedKeys);
});
(0, _ava.test)('[Structure] Given schema definition with no contexts, when final schema is built, then it should be no extra keys in it', t => {
const expectedKeys = ['default'];
var _fixtures$schemaWitho5 = fixtures.schemaWithoutCustomValidators,
_fixtures$schemaWitho6 = _fixtures$schemaWitho5.$contexts;
const $contexts = _fixtures$schemaWitho6 === undefined ? {} : _fixtures$schemaWitho6,
definition = _objectWithoutProperties(_fixtures$schemaWitho5, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(Object.keys(result), expectedKeys);
});
(0, _ava.test)('[Structure] Given schema definition with no contexts, when final schema is built, then it should have created the default schema with all keys from definition', t => {
var _fixtures$schemaWitho7 = fixtures.schemaWithoutCustomValidators,
_fixtures$schemaWitho8 = _fixtures$schemaWitho7.$contexts;
const $contexts = _fixtures$schemaWitho8 === undefined ? {} : _fixtures$schemaWitho8,
definition = _objectWithoutProperties(_fixtures$schemaWitho7, ['$contexts']);
const expectedKeys = Object.keys(definition);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(Object.keys(result.default), expectedKeys);
});
(0, _ava.test)('[Structure] Given schema definition with context, when final schema is built, then it should create a context schema', t => {
const expectedKeys = ['default', 'myContext'];
var _fixtures$schemaWithC = fixtures.schemaWithContext,
_fixtures$schemaWithC2 = _fixtures$schemaWithC.$contexts;
const $contexts = _fixtures$schemaWithC2 === undefined ? {} : _fixtures$schemaWithC2,
definition = _objectWithoutProperties(_fixtures$schemaWithC, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(Object.keys(result), expectedKeys);
});
(0, _ava.test)('[Structure] Given schema definition with context, when final schema is built, then it should not have a `$contexts` property on default schema', t => {
var _fixtures$schemaWithC3 = fixtures.schemaWithContext,
_fixtures$schemaWithC4 = _fixtures$schemaWithC3.$contexts;
const $contexts = _fixtures$schemaWithC4 === undefined ? {} : _fixtures$schemaWithC4,
definition = _objectWithoutProperties(_fixtures$schemaWithC3, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.false(result.default.hasOwnProperty('$contexts'));
});
(0, _ava.test)('[Validators] Given schema definition with no validators, when final schema is built, then it should use the default `allowAny` validator for leaf fields', t => {
var _fixtures$schemaWitho9 = fixtures.schemaWithoutCustomValidators,
_fixtures$schemaWitho10 = _fixtures$schemaWitho9.$contexts;
const $contexts = _fixtures$schemaWitho10 === undefined ? {} : _fixtures$schemaWitho10,
definition = _objectWithoutProperties(_fixtures$schemaWitho9, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.default.field1.validator, _defaultValidators.allowAny);
t.is(result.default.childEntity.validator, _defaultValidators.allowAny);
});
(0, _ava.test)('[Validators] Given schema definition with validators, when final schema is built, then it should not override the validator from definition', t => {
var _fixtures$schemaWithC5 = fixtures.schemaWithCustomValidators,
_fixtures$schemaWithC6 = _fixtures$schemaWithC5.$contexts;
const $contexts = _fixtures$schemaWithC6 === undefined ? {} : _fixtures$schemaWithC6,
definition = _objectWithoutProperties(_fixtures$schemaWithC5, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.default.field1.validator, fixtures.schemaWithCustomValidators.field1.validator);
t.is(result.default.childEntity.validator, fixtures.schemaWithCustomValidators.childEntity.validator);
});
(0, _ava.test)('[Default] Given schema definition with `default` option, when final schema is built, then it should have a `default` option defined as the input', t => {
var _fixtures$schemaWithD = fixtures.schemaWithDefault,
_fixtures$schemaWithD2 = _fixtures$schemaWithD.$contexts;
const $contexts = _fixtures$schemaWithD2 === undefined ? {} : _fixtures$schemaWithD2,
definition = _objectWithoutProperties(_fixtures$schemaWithD, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.default.field1.default, fixtures.schemaWithDefault.field1.default);
});
(0, _ava.test)('[Skippable] Given schema definition with no `skippable` option, when final schema is built, then it should have a `skippable` option defined to `false`', t => {
var _fixtures$schemaWithC7 = fixtures.schemaWithCustomValidators,
_fixtures$schemaWithC8 = _fixtures$schemaWithC7.$contexts;
const $contexts = _fixtures$schemaWithC8 === undefined ? {} : _fixtures$schemaWithC8,
definition = _objectWithoutProperties(_fixtures$schemaWithC7, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.default.field1.skippable, false);
t.is(result.default.childEntity.skippable, false);
});
(0, _ava.test)('[Skippable] Given schema definition with `skippable` option, when final schema is built, then it should have a `skippable` option as defined in schema', t => {
var _fixtures$schemaWithS = fixtures.schemaWithSkippable,
_fixtures$schemaWithS2 = _fixtures$schemaWithS.$contexts;
const $contexts = _fixtures$schemaWithS2 === undefined ? {} : _fixtures$schemaWithS2,
definition = _objectWithoutProperties(_fixtures$schemaWithS, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.default.field1.skippable, fixtures.schemaWithSkippable.field1.skippable);
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$exclude`, when final schema is built, then it should have a context schema excluding the properties declared', t => {
var _fixtures$schemaWithC9 = fixtures.schemaWithContextExclude,
_fixtures$schemaWithC10 = _fixtures$schemaWithC9.$contexts;
const $contexts = _fixtures$schemaWithC10 === undefined ? {} : _fixtures$schemaWithC10,
definition = _objectWithoutProperties(_fixtures$schemaWithC9, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(result.contextWithExclude, (0, _common.omit)(result.default, ['field1']));
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$include`, when final schema is built, then it should have a context schema including only the properties declared', t => {
var _fixtures$schemaWithC11 = fixtures.schemaWithContextInclude,
_fixtures$schemaWithC12 = _fixtures$schemaWithC11.$contexts;
const $contexts = _fixtures$schemaWithC12 === undefined ? {} : _fixtures$schemaWithC12,
definition = _objectWithoutProperties(_fixtures$schemaWithC11, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(result.contextWithInclude, (0, _common.pick)(result.default, ['field1']));
});
(0, _ava.test)('[Contexts] Given schema definition with a context using both `$include` and `$exclue`, when final schema is built, then it should have a context schema including only the properties declared in `$include`', t => {
var _fixtures$schemaWithC13 = fixtures.schemaWithContextIncludeAndExclude,
_fixtures$schemaWithC14 = _fixtures$schemaWithC13.$contexts;
const $contexts = _fixtures$schemaWithC14 === undefined ? {} : _fixtures$schemaWithC14,
definition = _objectWithoutProperties(_fixtures$schemaWithC13, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual(result.contextWithIncludeAndExclude, (0, _common.pick)(result.default, ['field1']));
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$modify`, when final schema is built, then it should have a context schema changing only the declared validators', t => {
var _fixtures$schemaWithC15 = fixtures.schemaWithContextModify,
_fixtures$schemaWithC16 = _fixtures$schemaWithC15.$contexts;
const $contexts = _fixtures$schemaWithC16 === undefined ? {} : _fixtures$schemaWithC16,
definition = _objectWithoutProperties(_fixtures$schemaWithC15, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.deepEqual((0, _common.omit)(result.contextWithModify, ['field1']), (0, _common.omit)(result.default, ['field1']));
t.is(result.contextWithModify.field1.validator, _defaultValidators.forbidAny);
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$modify` with extra properties, when final schema is built, then it should not create new properties in the result', t => {
var _fixtures$schemaWithC17 = fixtures.schemaWithContextModifyUnspecifiedProp,
_fixtures$schemaWithC18 = _fixtures$schemaWithC17.$contexts;
const $contexts = _fixtures$schemaWithC18 === undefined ? {} : _fixtures$schemaWithC18,
definition = _objectWithoutProperties(_fixtures$schemaWithC17, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.contextWithModifyUnspecifiedProp.unespecifiedField1, undefined);
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$include` and `$modify`, when final schema is built, then it should modify only the properties in `$include`', t => {
var _fixtures$schemaWithC19 = fixtures.schemaWithContextIncludeAndModify,
_fixtures$schemaWithC20 = _fixtures$schemaWithC19.$contexts;
const $contexts = _fixtures$schemaWithC20 === undefined ? {} : _fixtures$schemaWithC20,
definition = _objectWithoutProperties(_fixtures$schemaWithC19, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.contextWithIncludeAndModify.field1.validator, _defaultValidators.forbidAny);
t.is(result.contextWithIncludeAndModify.field2, undefined);
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$exclude` and `$modify`, when final schema is built, then it should modify only the properties not in `$exclude`', t => {
var _fixtures$schemaWithC21 = fixtures.schemaWithContextExcludeAndModify,
_fixtures$schemaWithC22 = _fixtures$schemaWithC21.$contexts;
const $contexts = _fixtures$schemaWithC22 === undefined ? {} : _fixtures$schemaWithC22,
definition = _objectWithoutProperties(_fixtures$schemaWithC21, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.contextWithExcludeAndModify.field1, undefined);
t.is(result.contextWithExcludeAndModify.field2.validator, _defaultValidators.forbidAny);
t.deepEqual((0, _common.omit)(result.contextWithExcludeAndModify, ['field1', 'field2']), (0, _common.omit)(result.default, ['field1', 'field2']));
});
(0, _ava.test)('[Contexts] Given schema definition with a context using `$skip`, when final schema is built, then it should modify only the properties in `$skip` to have the values set for `skippable` option', t => {
var _fixtures$schemaWithC23 = fixtures.schemaWithContextSkip,
_fixtures$schemaWithC24 = _fixtures$schemaWithC23.$contexts;
const $contexts = _fixtures$schemaWithC24 === undefined ? {} : _fixtures$schemaWithC24,
definition = _objectWithoutProperties(_fixtures$schemaWithC23, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.is(result.contextWithSkip.field1.skippable, true);
});
(0, _ava.test)('[Contexts] Given schema definition with multiple contexts, when final schema is built, then all contexts should be available', t => {
var _fixtures$schemaWithM = fixtures.schemaWithMultipleContexts,
_fixtures$schemaWithM2 = _fixtures$schemaWithM.$contexts;
const $contexts = _fixtures$schemaWithM2 === undefined ? {} : _fixtures$schemaWithM2,
definition = _objectWithoutProperties(_fixtures$schemaWithM, ['$contexts']);
const result = (0, _buildSchema2.default)(definition, $contexts);
t.true(result.hasOwnProperty('context1'));
t.true(result.hasOwnProperty('context2'));
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9idWlsZC1zY2hlbWEudGVzdC5qcyJdLCJuYW1lcyI6WyJmaXh0dXJlcyIsInQiLCJzY2hlbWFXaXRob3V0Q3VzdG9tVmFsaWRhdG9ycyIsIiRjb250ZXh0cyIsImRlZmluaXRpb24iLCJyZXN1bHQiLCJ0cnV0aHkiLCJkZWZhdWx0IiwiZXhwZWN0ZWRLZXlzIiwiZGVlcEVxdWFsIiwiT2JqZWN0Iiwia2V5cyIsInNjaGVtYVdpdGhDb250ZXh0IiwiZmFsc2UiLCJoYXNPd25Qcm9wZXJ0eSIsImlzIiwiZmllbGQxIiwidmFsaWRhdG9yIiwiY2hpbGRFbnRpdHkiLCJzY2hlbWFXaXRoQ3VzdG9tVmFsaWRhdG9ycyIsInNjaGVtYVdpdGhEZWZhdWx0Iiwic2tpcHBhYmxlIiwic2NoZW1hV2l0aFNraXBwYWJsZSIsInNjaGVtYVdpdGhDb250ZXh0RXhjbHVkZSIsImNvbnRleHRXaXRoRXhjbHVkZSIsInNjaGVtYVdpdGhDb250ZXh0SW5jbHVkZSIsImNvbnRleHRXaXRoSW5jbHVkZSIsInNjaGVtYVdpdGhDb250ZXh0SW5jbHVkZUFuZEV4Y2x1ZGUiLCJjb250ZXh0V2l0aEluY2x1ZGVBbmRFeGNsdWRlIiwic2NoZW1hV2l0aENvbnRleHRNb2RpZnkiLCJjb250ZXh0V2l0aE1vZGlmeSIsInNjaGVtYVdpdGhDb250ZXh0TW9kaWZ5VW5zcGVjaWZpZWRQcm9wIiwiY29udGV4dFdpdGhNb2RpZnlVbnNwZWNpZmllZFByb3AiLCJ1bmVzcGVjaWZpZWRGaWVsZDEiLCJ1bmRlZmluZWQiLCJzY2hlbWFXaXRoQ29udGV4dEluY2x1ZGVBbmRNb2RpZnkiLCJjb250ZXh0V2l0aEluY2x1ZGVBbmRNb2RpZnkiLCJmaWVsZDIiLCJzY2hlbWFXaXRoQ29udGV4dEV4Y2x1ZGVBbmRNb2RpZnkiLCJjb250ZXh0V2l0aEV4Y2x1ZGVBbmRNb2RpZnkiLCJzY2hlbWFXaXRoQ29udGV4dFNraXAiLCJjb250ZXh0V2l0aFNraXAiLCJzY2hlbWFXaXRoTXVsdGlwbGVDb250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QyxDQUFDLFFBQUQsRUFBVyxRQUFYLENBQXpDLENBREYsRUFFRSxrQkFBS2xDLE9BQU9FLE9BQVosRUFBcUIsQ0FBQyxRQUFELEVBQVcsUUFBWCxDQUFyQixDQUZGO0FBSUQsQ0FWRDs7QUFZQSxlQUFLLGlNQUFMLEVBQXdNTixLQUFLO0FBQUEsZ0NBQ2pLRCxTQUFTd0MscUJBRHdKO0FBQUEsd0RBQ25NckMsU0FEbU07O0FBQUEsUUFDbk1BLFNBRG1NLDJDQUN2TCxFQUR1TDtBQUFBLFFBQ2hMQyxVQURnTDs7QUFFM00sUUFBTUMsU0FBUywyQkFBUUQsVUFBUixFQUFvQkQsU0FBcEIsQ0FBZjs7QUFFQUYsSUFBRWMsRUFBRixDQUFLVixPQUFPb0MsZUFBUCxDQUF1QnpCLE1BQXZCLENBQThCSyxTQUFuQyxFQUE4QyxJQUE5QztBQUNELENBTEQ7O0FBT0EsZUFBSyw4SEFBTCxFQUFxSXBCLEtBQUs7QUFBQSw4QkFDOUZELFNBQVMwQywwQkFEcUY7QUFBQSxxREFDaEl2QyxTQURnSTs7QUFBQSxRQUNoSUEsU0FEZ0ksMENBQ3BILEVBRG9IO0FBQUEsUUFDN0dDLFVBRDZHOztBQUV4SSxRQUFNQyxTQUFTLDJCQUFRRCxVQUFSLEVBQW9CRCxTQUFwQixDQUFmOztBQUVBRixJQUFFMEMsSUFBRixDQUFPdEMsT0FBT1MsY0FBUCxDQUFzQixVQUF0QixDQUFQO0FBQ0FiLElBQUUwQyxJQUFGLENBQU90QyxPQUFPUyxjQUFQLENBQXNCLFVBQXRCLENBQVA7QUFDRCxDQU5EIiwiZmlsZSI6ImJ1aWxkLXNjaGVtYS50ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdGVzdCB9IGZyb20gJ2F2YSdcbmltcG9ydCBzdWJqZWN0IGZyb20gJy4vYnVpbGQtc2NoZW1hJ1xuXG5pbXBvcnQgeyBhbGxvd0FueSwgZm9yYmlkQW55IH0gZnJvbSAnLi9kZWZhdWx0LXZhbGlkYXRvcnMnXG5pbXBvcnQgeyBvbWl0LCBwaWNrIH0gZnJvbSAnLi9jb21tb24nXG5pbXBvcnQgKiBhcyBmaXh0dXJlcyBmcm9tICcuL2J1aWxkLXNjaGVtYS5maXh0dXJlJ1xuXG50ZXN0KCdbU3RydWN0dXJlXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiwgd2hlbiBmaW5hbCBzY2hlbWEgaXMgYnVpbHQsIHRoZW4gaXQgc2hvdWxkIGhhdmUgY3JlYXRlZCB0aGUgZGVmYXVsdCBzY2hlbWEnLCB0ID0+IHtcbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aG91dEN1c3RvbVZhbGlkYXRvcnNcbiAgY29uc3QgcmVzdWx0ID0gc3ViamVjdChkZWZpbml0aW9uLCAkY29udGV4dHMpXG5cbiAgdC50cnV0aHkocmVzdWx0LmRlZmF1bHQpXG59KVxuXG50ZXN0KCdbU3RydWN0dXJlXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIG5vIGNvbnRleHRzLCB3aGVuIGZpbmFsIHNjaGVtYSBpcyBidWlsdCwgdGhlbiBpdCBzaG91bGQgYmUgbm8gZXh0cmEga2V5cyBpbiBpdCcsIHQgPT4ge1xuICBjb25zdCBleHBlY3RlZEtleXMgPSBbJ2RlZmF1bHQnXVxuXG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhvdXRDdXN0b21WYWxpZGF0b3JzXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuZGVlcEVxdWFsKE9iamVjdC5rZXlzKHJlc3VsdCksIGV4cGVjdGVkS2V5cylcbn0pXG5cbnRlc3QoJ1tTdHJ1Y3R1cmVdIEdpdmVuIHNjaGVtYSBkZWZpbml0aW9uIHdpdGggbm8gY29udGV4dHMsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCBiZSBubyBleHRyYSBrZXlzIGluIGl0JywgdCA9PiB7XG4gIGNvbnN0IGV4cGVjdGVkS2V5cyA9IFsnZGVmYXVsdCddXG5cbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aG91dEN1c3RvbVZhbGlkYXRvcnNcbiAgY29uc3QgcmVzdWx0ID0gc3ViamVjdChkZWZpbml0aW9uLCAkY29udGV4dHMpXG5cbiAgdC5kZWVwRXF1YWwoT2JqZWN0LmtleXMocmVzdWx0KSwgZXhwZWN0ZWRLZXlzKVxufSlcblxudGVzdCgnW1N0cnVjdHVyZV0gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBubyBjb250ZXh0cywgd2hlbiBmaW5hbCBzY2hlbWEgaXMgYnVpbHQsIHRoZW4gaXQgc2hvdWxkIGhhdmUgY3JlYXRlZCB0aGUgZGVmYXVsdCBzY2hlbWEgd2l0aCBhbGwga2V5cyBmcm9tIGRlZmluaXRpb24nLCB0ID0+IHtcbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aG91dEN1c3RvbVZhbGlkYXRvcnNcblxuICBjb25zdCBleHBlY3RlZEtleXMgPSBPYmplY3Qua2V5cyhkZWZpbml0aW9uKVxuXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuZGVlcEVxdWFsKE9iamVjdC5rZXlzKHJlc3VsdC5kZWZhdWx0KSwgZXhwZWN0ZWRLZXlzKVxufSlcblxudGVzdCgnW1N0cnVjdHVyZV0gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBjb250ZXh0LCB3aGVuIGZpbmFsIHNjaGVtYSBpcyBidWlsdCwgdGhlbiBpdCBzaG91bGQgY3JlYXRlIGEgY29udGV4dCBzY2hlbWEnLCB0ID0+IHtcbiAgY29uc3QgZXhwZWN0ZWRLZXlzID0gWydkZWZhdWx0JywgJ215Q29udGV4dCddXG5cbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aENvbnRleHRcbiAgY29uc3QgcmVzdWx0ID0gc3ViamVjdChkZWZpbml0aW9uLCAkY29udGV4dHMpXG5cbiAgdC5kZWVwRXF1YWwoT2JqZWN0LmtleXMocmVzdWx0KSwgZXhwZWN0ZWRLZXlzKVxufSlcblxudGVzdCgnW1N0cnVjdHVyZV0gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBjb250ZXh0LCB3aGVuIGZpbmFsIHNjaGVtYSBpcyBidWlsdCwgdGhlbiBpdCBzaG91bGQgbm90IGhhdmUgYSBgJGNvbnRleHRzYCBwcm9wZXJ0eSBvbiBkZWZhdWx0IHNjaGVtYScsIHQgPT4ge1xuICBjb25zdCB7ICRjb250ZXh0cyA9IHt9LCAuLi5kZWZpbml0aW9uIH0gPSBmaXh0dXJlcy5zY2hlbWFXaXRoQ29udGV4dFxuICBjb25zdCByZXN1bHQgPSBzdWJqZWN0KGRlZmluaXRpb24sICRjb250ZXh0cylcblxuICB0LmZhbHNlKHJlc3VsdC5kZWZhdWx0Lmhhc093blByb3BlcnR5KCckY29udGV4dHMnKSlcbn0pXG5cbnRlc3QoJ1tWYWxpZGF0b3JzXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIG5vIHZhbGlkYXRvcnMsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCB1c2UgdGhlIGRlZmF1bHQgYGFsbG93QW55YCB2YWxpZGF0b3IgZm9yIGxlYWYgZmllbGRzJywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhvdXRDdXN0b21WYWxpZGF0b3JzXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuaXMocmVzdWx0LmRlZmF1bHQuZmllbGQxLnZhbGlkYXRvciwgYWxsb3dBbnkpXG4gIHQuaXMocmVzdWx0LmRlZmF1bHQuY2hpbGRFbnRpdHkudmFsaWRhdG9yLCBhbGxvd0FueSlcbn0pXG5cbnRlc3QoJ1tWYWxpZGF0b3JzXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIHZhbGlkYXRvcnMsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCBub3Qgb3ZlcnJpZGUgdGhlIHZhbGlkYXRvciBmcm9tIGRlZmluaXRpb24nLCB0ID0+IHtcbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aEN1c3RvbVZhbGlkYXRvcnNcbiAgY29uc3QgcmVzdWx0ID0gc3ViamVjdChkZWZpbml0aW9uLCAkY29udGV4dHMpXG5cbiAgdC5pcyhyZXN1bHQuZGVmYXVsdC5maWVsZDEudmFsaWRhdG9yLCBmaXh0dXJlcy5zY2hlbWFXaXRoQ3VzdG9tVmFsaWRhdG9ycy5maWVsZDEudmFsaWRhdG9yKVxuICB0LmlzKHJlc3VsdC5kZWZhdWx0LmNoaWxkRW50aXR5LnZhbGlkYXRvciwgZml4dHVyZXMuc2NoZW1hV2l0aEN1c3RvbVZhbGlkYXRvcnMuY2hpbGRFbnRpdHkudmFsaWRhdG9yKVxufSlcblxudGVzdCgnW0RlZmF1bHRdIEdpdmVuIHNjaGVtYSBkZWZpbml0aW9uIHdpdGggYGRlZmF1bHRgIG9wdGlvbiwgd2hlbiBmaW5hbCBzY2hlbWEgaXMgYnVpbHQsIHRoZW4gaXQgc2hvdWxkIGhhdmUgYSBgZGVmYXVsdGAgb3B0aW9uIGRlZmluZWQgYXMgdGhlIGlucHV0JywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhEZWZhdWx0XG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuaXMocmVzdWx0LmRlZmF1bHQuZmllbGQxLmRlZmF1bHQsIGZpeHR1cmVzLnNjaGVtYVdpdGhEZWZhdWx0LmZpZWxkMS5kZWZhdWx0KVxufSlcblxudGVzdCgnW1NraXBwYWJsZV0gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBubyBgc2tpcHBhYmxlYCBvcHRpb24sIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCBoYXZlIGEgYHNraXBwYWJsZWAgb3B0aW9uIGRlZmluZWQgdG8gYGZhbHNlYCcsIHQgPT4ge1xuICBjb25zdCB7ICRjb250ZXh0cyA9IHt9LCAuLi5kZWZpbml0aW9uIH0gPSBmaXh0dXJlcy5zY2hlbWFXaXRoQ3VzdG9tVmFsaWRhdG9yc1xuICBjb25zdCByZXN1bHQgPSBzdWJqZWN0KGRlZmluaXRpb24sICRjb250ZXh0cylcblxuICB0LmlzKHJlc3VsdC5kZWZhdWx0LmZpZWxkMS5za2lwcGFibGUsIGZhbHNlKVxuICB0LmlzKHJlc3VsdC5kZWZhdWx0LmNoaWxkRW50aXR5LnNraXBwYWJsZSwgZmFsc2UpXG59KVxuXG50ZXN0KCdbU2tpcHBhYmxlXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIGBza2lwcGFibGVgIG9wdGlvbiwgd2hlbiBmaW5hbCBzY2hlbWEgaXMgYnVpbHQsIHRoZW4gaXQgc2hvdWxkIGhhdmUgYSBgc2tpcHBhYmxlYCBvcHRpb24gYXMgZGVmaW5lZCBpbiBzY2hlbWEnLCB0ID0+IHtcbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aFNraXBwYWJsZVxuICBjb25zdCByZXN1bHQgPSBzdWJqZWN0KGRlZmluaXRpb24sICRjb250ZXh0cylcblxuICB0LmlzKHJlc3VsdC5kZWZhdWx0LmZpZWxkMS5za2lwcGFibGUsIGZpeHR1cmVzLnNjaGVtYVdpdGhTa2lwcGFibGUuZmllbGQxLnNraXBwYWJsZSlcbn0pXG5cbnRlc3QoJ1tDb250ZXh0c10gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBhIGNvbnRleHQgdXNpbmcgYCRleGNsdWRlYCwgd2hlbiBmaW5hbCBzY2hlbWEgaXMgYnVpbHQsIHRoZW4gaXQgc2hvdWxkIGhhdmUgYSBjb250ZXh0IHNjaGVtYSBleGNsdWRpbmcgdGhlIHByb3BlcnRpZXMgZGVjbGFyZWQnLCB0ID0+IHtcbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aENvbnRleHRFeGNsdWRlXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuZGVlcEVxdWFsKHJlc3VsdC5jb250ZXh0V2l0aEV4Y2x1ZGUsIG9taXQocmVzdWx0LmRlZmF1bHQsIFsnZmllbGQxJ10pKVxufSlcblxudGVzdCgnW0NvbnRleHRzXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIGEgY29udGV4dCB1c2luZyBgJGluY2x1ZGVgLCB3aGVuIGZpbmFsIHNjaGVtYSBpcyBidWlsdCwgdGhlbiBpdCBzaG91bGQgaGF2ZSBhIGNvbnRleHQgc2NoZW1hIGluY2x1ZGluZyBvbmx5IHRoZSBwcm9wZXJ0aWVzIGRlY2xhcmVkJywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhDb250ZXh0SW5jbHVkZVxuICBjb25zdCByZXN1bHQgPSBzdWJqZWN0KGRlZmluaXRpb24sICRjb250ZXh0cylcblxuICB0LmRlZXBFcXVhbChyZXN1bHQuY29udGV4dFdpdGhJbmNsdWRlLCBwaWNrKHJlc3VsdC5kZWZhdWx0LCBbJ2ZpZWxkMSddKSlcbn0pXG5cbnRlc3QoJ1tDb250ZXh0c10gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBhIGNvbnRleHQgdXNpbmcgYm90aCBgJGluY2x1ZGVgIGFuZCBgJGV4Y2x1ZWAsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCBoYXZlIGEgY29udGV4dCBzY2hlbWEgaW5jbHVkaW5nIG9ubHkgdGhlIHByb3BlcnRpZXMgZGVjbGFyZWQgaW4gYCRpbmNsdWRlYCcsIHQgPT4ge1xuICBjb25zdCB7ICRjb250ZXh0cyA9IHt9LCAuLi5kZWZpbml0aW9uIH0gPSBmaXh0dXJlcy5zY2hlbWFXaXRoQ29udGV4dEluY2x1ZGVBbmRFeGNsdWRlXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuZGVlcEVxdWFsKHJlc3VsdC5jb250ZXh0V2l0aEluY2x1ZGVBbmRFeGNsdWRlLCBwaWNrKHJlc3VsdC5kZWZhdWx0LCBbJ2ZpZWxkMSddKSlcbn0pXG5cbnRlc3QoJ1tDb250ZXh0c10gR2l2ZW4gc2NoZW1hIGRlZmluaXRpb24gd2l0aCBhIGNvbnRleHQgdXNpbmcgYCRtb2RpZnlgLCB3aGVuIGZpbmFsIHNjaGVtYSBpcyBidWlsdCwgdGhlbiBpdCBzaG91bGQgaGF2ZSBhIGNvbnRleHQgc2NoZW1hIGNoYW5naW5nIG9ubHkgdGhlIGRlY2xhcmVkIHZhbGlkYXRvcnMnLCB0ID0+IHtcbiAgY29uc3QgeyAkY29udGV4dHMgPSB7fSwgLi4uZGVmaW5pdGlvbiB9ID0gZml4dHVyZXMuc2NoZW1hV2l0aENvbnRleHRNb2RpZnlcbiAgY29uc3QgcmVzdWx0ID0gc3ViamVjdChkZWZpbml0aW9uLCAkY29udGV4dHMpXG5cbiAgdC5kZWVwRXF1YWwob21pdChyZXN1bHQuY29udGV4dFdpdGhNb2RpZnksIFsnZmllbGQxJ10pLCBvbWl0KHJlc3VsdC5kZWZhdWx0LCBbJ2ZpZWxkMSddKSlcbiAgdC5pcyhyZXN1bHQuY29udGV4dFdpdGhNb2RpZnkuZmllbGQxLnZhbGlkYXRvciwgZm9yYmlkQW55KVxufSlcblxudGVzdCgnW0NvbnRleHRzXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIGEgY29udGV4dCB1c2luZyBgJG1vZGlmeWAgd2l0aCBleHRyYSBwcm9wZXJ0aWVzLCB3aGVuIGZpbmFsIHNjaGVtYSBpcyBidWlsdCwgdGhlbiBpdCBzaG91bGQgbm90IGNyZWF0ZSBuZXcgcHJvcGVydGllcyBpbiB0aGUgcmVzdWx0JywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhDb250ZXh0TW9kaWZ5VW5zcGVjaWZpZWRQcm9wXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQuaXMocmVzdWx0LmNvbnRleHRXaXRoTW9kaWZ5VW5zcGVjaWZpZWRQcm9wLnVuZXNwZWNpZmllZEZpZWxkMSwgdW5kZWZpbmVkKVxufSlcblxudGVzdCgnW0NvbnRleHRzXSBHaXZlbiBzY2hlbWEgZGVmaW5pdGlvbiB3aXRoIGEgY29udGV4dCB1c2luZyBgJGluY2x1ZGVgIGFuZCBgJG1vZGlmeWAsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCBtb2RpZnkgb25seSB0aGUgcHJvcGVydGllcyBpbiBgJGluY2x1ZGVgJywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhDb250ZXh0SW5jbHVkZUFuZE1vZGlmeVxuICBjb25zdCByZXN1bHQgPSBzdWJqZWN0KGRlZmluaXRpb24sICRjb250ZXh0cylcblxuICB0LmlzKHJlc3VsdC5jb250ZXh0V2l0aEluY2x1ZGVBbmRNb2RpZnkuZmllbGQxLnZhbGlkYXRvciwgZm9yYmlkQW55KVxuICB0LmlzKHJlc3VsdC5jb250ZXh0V2l0aEluY2x1ZGVBbmRNb2RpZnkuZmllbGQyLCB1bmRlZmluZWQpXG59KVxuXG50ZXN0KCdbQ29udGV4dHNdIEdpdmVuIHNjaGVtYSBkZWZpbml0aW9uIHdpdGggYSBjb250ZXh0IHVzaW5nIGAkZXhjbHVkZWAgYW5kIGAkbW9kaWZ5YCwgd2hlbiBmaW5hbCBzY2hlbWEgaXMgYnVpbHQsIHRoZW4gaXQgc2hvdWxkIG1vZGlmeSBvbmx5IHRoZSBwcm9wZXJ0aWVzIG5vdCBpbiBgJGV4Y2x1ZGVgJywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhDb250ZXh0RXhjbHVkZUFuZE1vZGlmeVxuICBjb25zdCByZXN1bHQgPSBzdWJqZWN0KGRlZmluaXRpb24sICRjb250ZXh0cylcblxuICB0LmlzKHJlc3VsdC5jb250ZXh0V2l0aEV4Y2x1ZGVBbmRNb2RpZnkuZmllbGQxLCB1bmRlZmluZWQpXG4gIHQuaXMocmVzdWx0LmNvbnRleHRXaXRoRXhjbHVkZUFuZE1vZGlmeS5maWVsZDIudmFsaWRhdG9yLCBmb3JiaWRBbnkpXG4gIHQuZGVlcEVxdWFsKFxuICAgIG9taXQocmVzdWx0LmNvbnRleHRXaXRoRXhjbHVkZUFuZE1vZGlmeSwgWydmaWVsZDEnLCAnZmllbGQyJ10pLFxuICAgIG9taXQocmVzdWx0LmRlZmF1bHQsIFsnZmllbGQxJywgJ2ZpZWxkMiddKVxuICApXG59KVxuXG50ZXN0KCdbQ29udGV4dHNdIEdpdmVuIHNjaGVtYSBkZWZpbml0aW9uIHdpdGggYSBjb250ZXh0IHVzaW5nIGAkc2tpcGAsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGl0IHNob3VsZCBtb2RpZnkgb25seSB0aGUgcHJvcGVydGllcyBpbiBgJHNraXBgIHRvIGhhdmUgdGhlIHZhbHVlcyBzZXQgZm9yIGBza2lwcGFibGVgIG9wdGlvbicsIHQgPT4ge1xuICBjb25zdCB7ICRjb250ZXh0cyA9IHt9LCAuLi5kZWZpbml0aW9uIH0gPSBmaXh0dXJlcy5zY2hlbWFXaXRoQ29udGV4dFNraXBcbiAgY29uc3QgcmVzdWx0ID0gc3ViamVjdChkZWZpbml0aW9uLCAkY29udGV4dHMpXG5cbiAgdC5pcyhyZXN1bHQuY29udGV4dFdpdGhTa2lwLmZpZWxkMS5za2lwcGFibGUsIHRydWUpXG59KVxuXG50ZXN0KCdbQ29udGV4dHNdIEdpdmVuIHNjaGVtYSBkZWZpbml0aW9uIHdpdGggbXVsdGlwbGUgY29udGV4dHMsIHdoZW4gZmluYWwgc2NoZW1hIGlzIGJ1aWx0LCB0aGVuIGFsbCBjb250ZXh0cyBzaG91bGQgYmUgYXZhaWxhYmxlJywgdCA9PiB7XG4gIGNvbnN0IHsgJGNvbnRleHRzID0ge30sIC4uLmRlZmluaXRpb24gfSA9IGZpeHR1cmVzLnNjaGVtYVdpdGhNdWx0aXBsZUNvbnRleHRzXG4gIGNvbnN0IHJlc3VsdCA9IHN1YmplY3QoZGVmaW5pdGlvbiwgJGNvbnRleHRzKVxuXG4gIHQudHJ1ZShyZXN1bHQuaGFzT3duUHJvcGVydHkoJ2NvbnRleHQxJykpXG4gIHQudHJ1ZShyZXN1bHQuaGFzT3duUHJvcGVydHkoJ2NvbnRleHQyJykpXG59KVxuIl19