UNPKG

speckoloo

Version:
716 lines (560 loc) 57.2 kB
'use strict'; var _ava = require('ava'); var _index = require('./index'); var _common = require('./common'); const validators = { requiredString: (value, field, data) => { if (typeof value !== 'string') { return { error: [`${field} should be a non-empty string`] }; } return { data }; }, requiredNumber: (value, field, data) => { if (typeof value !== 'number') { return { error: [`${field} should be a valid number`] }; } return { data }; } }; (0, _ava.test)('Given entity with default value for property, when it is created without such property, then it should set the property to the default value', t => { const schema = { prop1: { default: '__default__' } }; const emptyData = {}; const factory = (0, _index.factoryFor)(schema); const instance = factory(emptyData); t.is(instance.prop1, '__default__'); }); (0, _ava.test)('Given entity with one property with default value and other without default, when it is created without such property, then it should set the former to the default value', t => { const schema = { prop0: {}, prop1: { default: '__default__' }, prop2: {} }; const emptyData = {}; const factory = (0, _index.factoryFor)(schema); const instance = factory(emptyData); t.is(instance.prop1, '__default__'); }); (0, _ava.test)('Given entity with one property with default value, when factory is called without such property and with `ignoreDefaults` option set to `true`, then it should not set the property to the default value', t => { const schema = { prop1: { default: '__default__' } }; const emptyData = {}; const factory = (0, _index.factoryFor)(schema); const instance = factory(emptyData, { ignoreDefaults: true }); t.is(instance.prop1, undefined); }); (0, _ava.test)('Given entity with `readOnly` property, when trying to set such property, then it should throw an error', t => { const schema = { prop1: { readOnly: true } }; const validData = { prop1: '__initial__' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); const error = t.throws(() => { instance.prop1 = '__new__'; }); t.is(error.name, 'TypeError'); }); (0, _ava.test)('Given entity with validation and valid data, when validate is called, then it should not throw and return itself', t => { const schema = { prop1: { validator: validators.requiredString } }; const validData = { prop1: 'a' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); const result = instance.validate(); t.is(result, instance); }); (0, _ava.test)('Given entity with validation and invalid data, when validate is called, then it should throw', t => { const schema = { prop1: { validator: validators.requiredString }, prop2: { validator: validators.requiredString } }; const invalidData = { prop1: 'a' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(invalidData); const error = t.throws(() => { instance.validate(); }); t.is(error.code, 'ERR_VALIDATION'); t.true(error.details.hasOwnProperty('prop2')); }); (0, _ava.test)('Given entity with factory and valid data, when factory is called, then it return an object containing the property', t => { const schema = { prop1: { factory: Number }, prop2: { factory: Number } }; const validData = { prop1: '1000', prop2: 1001 }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); t.deepEqual(instance.toJSON(), { prop1: 1000, prop2: 1001 }); }); (0, _ava.test)('Given entity with nested entity and valid data, when validate is called, then it should not throw and return itself', t => { const childSchema = { childProp1: { validator: validators.requiredString } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { validator: _index.defaultValidators.delegate(), factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const validData = { childEntity: { childProp1: 'a' } }; const instance = parentFactory(validData); const result = instance.validate(); t.is(result, instance); }); (0, _ava.test)('Given entity with missing validator for primitive properties, when validate is called, then it should not throw and return itself', t => { const schema = { prop1: {}, prop2: {} }; const emptyData = {}; const factory = (0, _index.factoryFor)(schema); const instance = factory(emptyData); const result = instance.validate(); t.is(result, instance); }); (0, _ava.test)('Given entity with missing validator for nested entity property with valid data, when validate is called, then it should not throw and return itself', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const validData = { childEntity: { childProp1: 'a', childProp2: 'a' } }; const instance = parentFactory(validData); const result = instance.validate(); t.is(result, instance); }); (0, _ava.test)('Given entity with missing validator for nested entity property with invalidData, when validate is called, then it should not throw and return itself', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const invalidData = { childEntity: { childProp1: 'a' } }; const instance = parentFactory(invalidData); const result = instance.validate(); t.is(result, instance); }); (0, _ava.test)('Given entity with nested entity with `delegate` validator and invalid data, when validate is called, then it should throw', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { validator: _index.defaultValidators.delegate(), factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const invalidData = { childEntity: { childProp1: 'a' } }; const instance = parentFactory(invalidData); const error = t.throws(() => instance.validate()); t.is(error.code, 'ERR_VALIDATION'); t.true(error.details.hasOwnProperty('childEntity')); t.true(error.details.childEntity.hasOwnProperty('childProp2')); }); (0, _ava.test)('Given entity with nested entity with `delegate` validator with `required` option = true and data missing for nested, when validate is called, then it should throw', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { validator: _index.defaultValidators.delegate({ required: true }), factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const invalidData = {}; const instance = parentFactory(invalidData); const error = t.throws(() => instance.validate()); t.is(error.code, 'ERR_VALIDATION'); t.notRegex(error.message, /cannot read property 'validate' of undefined/i); t.true(error.details.hasOwnProperty('childEntity')); }); (0, _ava.test)('Given entity with nested entity with `delegate` validator with context and `required` option = true and data missing for nested, when validate is called, then it should throw', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString }, $contexts: { myContext: {} } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { validator: _index.defaultValidators.delegate('myContext', { required: true }), factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const invalidData = {}; const instance = parentFactory(invalidData); const error = t.throws(() => instance.validate()); t.is(error.code, 'ERR_VALIDATION'); t.notRegex(error.message, /cannot read property 'validate' of undefined/i); t.true(error.details.hasOwnProperty('childEntity')); }); (0, _ava.test)('Given entity with nested entity with `delegate` validator for a given context and valid data for such context, when validate is called, then it should not throw and return itself', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString }, $contexts: { myContext: { $exclude: ['childProp2'] } } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { validator: _index.defaultValidators.delegate('myContext'), factory: childFactory } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const validDataForContext = { childEntity: { childProp1: 'a' } }; const instance = parentFactory(validDataForContext); t.is(instance.validate(), instance); }); (0, _ava.test)('Given entity with context that excludes `prop2` and invalid data `prop2`, when validate is called with such context, then it should not throw and return itself', t => { const schema = { prop1: { validator: validators.requiredString }, prop2: { validator: validators.requiredString }, $contexts: { myContext: { $exclude: ['prop2'] } } }; const invalidData = { prop1: 'a' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(invalidData); const result = instance.validate('myContext'); t.is(result, instance); }); (0, _ava.test)('Given entity with context that modifies `prop2` and valid data for such context, when validate is called with such context, then it should use the validator from the context definition', t => { const schema = { prop1: { validator: validators.requiredString }, prop2: { validator: validators.requiredString }, $contexts: { myContext: { $modify: { prop2: validators.requiredNumber } } } }; const validDataForContext = { prop1: 'a', prop2: 1 }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validDataForContext); const result = instance.validate('myContext'); t.is(result, instance); }); (0, _ava.test)('Given entity with context that excludes `prop2`, when `toJSON()` is called with such context, then it should omit `prop2` from the result', t => { const schema = { prop1: {}, prop2: {}, $contexts: { myContext: { $exclude: ['prop2'] } } }; const validData = { prop1: 'a', prop2: 'b' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); const result = instance.toJSON('myContext'); t.deepEqual(result, (0, _common.omit)(validData, ['prop2'])); }); (0, _ava.test)('Given entity with context that includes `prop1`, when `toJSON()` is called with such context, then it should return an object containing only `prop1`', t => { const schema = { prop1: {}, prop2: {}, $contexts: { myContext: { $include: ['prop1'] } } }; const validData = { prop1: 'a', prop2: 'b' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); const result = instance.toJSON('myContext'); t.deepEqual(result, (0, _common.pick)(validData, ['prop1'])); }); (0, _ava.test)('Given invalid context, when `validate()` is called, then it should throw an error', t => { const schema = { prop1: {} }; const validData = { prop1: 'a' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); const error = t.throws(() => instance.validate('unexistentContext')); t.regex(error.message, /invalid context/i); }); (0, _ava.test)('Given invalid context, when `toJSON()` is called, then it should throw an error', t => { const schema = { prop1: {} }; const validData = { prop1: 'a' }; const factory = (0, _index.factoryFor)(schema); const instance = factory(validData); const error = t.throws(() => instance.toJSON('unexistentContext')); t.regex(error.message, /invalid context/i); }); (0, _ava.test)('Give entity with nested entity collection and valid data, when `toJSON()` is called, then it should return the original data', t => { const childSchema = { childProp1: {}, childProp2: {} }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { children: { factory: (0, _index.collectionFactoryFor)(childFactory) } }; const factory = (0, _index.factoryFor)(parentSchema); const validData = { children: [{ childProp1: 'a', childProp2: 'b' }, { childProp1: 'c', childProp2: 'd' }] }; const instance = factory(validData); t.deepEqual(instance.toJSON(), validData); }); (0, _ava.test)('Give entity with nested entity collection and invalid data, when `validate()` is called, then it should throw an error with appropriate error descriptions', t => { const childSchema = { childProp1: { validator: _index.defaultValidators.forbidAny }, childProp2: { validator: _index.defaultValidators.forbidAny } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { children: { validator: _index.defaultValidators.delegate(), factory: (0, _index.collectionFactoryFor)(childFactory) } }; const factory = (0, _index.factoryFor)(parentSchema); const invalidData = { children: [{ childProp1: 'a', childProp2: 'b' }, { childProp1: 'c', childProp2: 'd' }] }; const instance = factory(invalidData); const error = t.throws(() => instance.validate()); t.truthy(error.details.children['item#0'].childProp1); t.truthy(error.details.children['item#0'].childProp2); t.truthy(error.details.children['item#1'].childProp1); t.truthy(error.details.children['item#1'].childProp2); }); (0, _ava.test)('Given entity with nested entity with <context> and overriden `delegate` validator for a given context and valid data for such context, when `validate(<context>)` is called, then it should not throw and return itself', t => { const childSchema = { childProp1: { validator: validators.requiredString }, childProp2: { validator: validators.requiredString }, $contexts: { myContext: { $exclude: ['childProp2'] } } }; const childFactory = (0, _index.factoryFor)(childSchema); const parentSchema = { childEntity: { validator: _index.defaultValidators.delegate(), factory: childFactory }, $contexts: { parentContext: { $modify: { childEntity: _index.defaultValidators.delegate('myContext') } } } }; const parentFactory = (0, _index.factoryFor)(parentSchema); const validDataForContext = { childEntity: { childProp1: 'a' } }; const instance = parentFactory(validDataForContext); t.is(instance.validate('parentContext'), instance); }); (0, _ava.test)('Given simple schema, when setting a property, then it should modify the original entity', t => { 'use strict'; const schema = { prop1: { factory: Number } }; const factory = (0, _index.factoryFor)(schema); const instance = factory({}); instance.prop1 = '1'; t.is(instance.prop1, 1); }); (0, _ava.test)('Given schema with default value, when setting a property, then it should modify the original entity', t => { 'use strict'; const schema = { prop1: { default: '__default__' } }; const factory = (0, _index.factoryFor)(schema); const instance = factory({}); instance.prop1 = 'myValue'; t.is(instance.prop1, 'myValue'); }); (0, _ava.test)('Given schema with method that changes the entity, when calling such method, then it should modify the original entity', t => { const schema = { prop1: {}, $methods: { change() { this.prop1 = 'changedValue'; return this; } } }; const factory = (0, _index.factoryFor)(schema); const instance = factory({}); t.is(instance.change().prop1, 'changedValue'); }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50ZXN0LmpzIl0sIm5hbWVzIjpbInZhbGlkYXRvcnMiLCJyZXF1aXJlZFN0cmluZyIsInZhbHVlIiwiZmllbGQiLCJkYXRhIiwiZXJyb3IiLCJyZXF1aXJlZE51bWJlciIsInQiLCJzY2hlbWEiLCJwcm9wMSIsImRlZmF1bHQiLCJlbXB0eURhdGEiLCJmYWN0b3J5IiwiaW5zdGFuY2UiLCJpcyIsInByb3AwIiwicHJvcDIiLCJpZ25vcmVEZWZhdWx0cyIsInVuZGVmaW5lZCIsInJlYWRPbmx5IiwidmFsaWREYXRhIiwidGhyb3dzIiwibmFtZSIsInZhbGlkYXRvciIsInJlc3VsdCIsInZhbGlkYXRlIiwiaW52YWxpZERhdGEiLCJjb2RlIiwidHJ1ZSIsImRldGFpbHMiLCJoYXNPd25Qcm9wZXJ0eSIsIk51bWJlciIsImRlZXBFcXVhbCIsInRvSlNPTiIsImNoaWxkU2NoZW1hIiwiY2hpbGRQcm9wMSIsImNoaWxkRmFjdG9yeSIsInBhcmVudFNjaGVtYSIsImNoaWxkRW50aXR5IiwiZGVsZWdhdGUiLCJwYXJlbnRGYWN0b3J5IiwiY2hpbGRQcm9wMiIsInJlcXVpcmVkIiwibm90UmVnZXgiLCJtZXNzYWdlIiwiJGNvbnRleHRzIiwibXlDb250ZXh0IiwiJGV4Y2x1ZGUiLCJ2YWxpZERhdGFGb3JDb250ZXh0IiwiJG1vZGlmeSIsIiRpbmNsdWRlIiwicmVnZXgiLCJjaGlsZHJlbiIsImZvcmJpZEFueSIsInRydXRoeSIsInBhcmVudENvbnRleHQiLCIkbWV0aG9kcyIsImNoYW5nZSJdLCJtYXBwaW5ncyI6Ijs7QUFBQTs7QUFDQTs7QUFDQTs7QUFFQSxNQUFNQSxhQUFhO0FBQ2pCQyxrQkFBZ0IsQ0FBQ0MsS0FBRCxFQUFRQyxLQUFSLEVBQWVDLElBQWYsS0FBd0I7QUFDdEMsUUFBSSxPQUFPRixLQUFQLEtBQWlCLFFBQXJCLEVBQStCO0FBQzdCLGFBQU87QUFDTEcsZUFBTyxDQUFFLEdBQUVGLEtBQU0sK0JBQVY7QUFERixPQUFQO0FB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cm9tICdhdmEnXG5pbXBvcnQgeyBmYWN0b3J5Rm9yLCBjb2xsZWN0aW9uRmFjdG9yeUZvciwgZGVmYXVsdFZhbGlkYXRvcnMgfSBmcm9tICcuL2luZGV4J1xuaW1wb3J0IHsgb21pdCwgcGljayB9IGZyb20gJy4vY29tbW9uJ1xuXG5jb25zdCB2YWxpZGF0b3JzID0ge1xuICByZXF1aXJlZFN0cmluZzogKHZhbHVlLCBmaWVsZCwgZGF0YSkgPT4ge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBlcnJvcjogW2Ake2ZpZWxkfSBzaG91bGQgYmUgYSBub24tZW1wdHkgc3RyaW5nYF1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4geyBkYXRhIH1cbiAgfSxcbiAgcmVxdWlyZWROdW1iZXI6ICh2YWx1ZSwgZmllbGQsIGRhdGEpID0+IHtcbiAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnbnVtYmVyJykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZXJyb3I6IFtgJHtmaWVsZH0gc2hvdWxkIGJlIGEgdmFsaWQgbnVtYmVyYF1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4geyBkYXRhIH1cbiAgfVxufVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCBkZWZhdWx0IHZhbHVlIGZvciBwcm9wZXJ0eSwgd2hlbiBpdCBpcyBjcmVhdGVkIHdpdGhvdXQgc3VjaCBwcm9wZXJ0eSwgdGhlbiBpdCBzaG91bGQgc2V0IHRoZSBwcm9wZXJ0eSB0byB0aGUgZGVmYXVsdCB2YWx1ZScsIHQgPT4ge1xuICBjb25zdCBzY2hlbWEgPSB7XG4gICAgcHJvcDE6IHtcbiAgICAgIGRlZmF1bHQ6ICdfX2RlZmF1bHRfXydcbiAgICB9XG4gIH1cblxuICBjb25zdCBlbXB0eURhdGEgPSB7fVxuXG4gIGNvbnN0IGZhY3RvcnkgPSBmYWN0b3J5Rm9yKHNjaGVtYSlcblxuICBjb25zdCBpbnN0YW5jZSA9IGZhY3RvcnkoZW1wdHlEYXRhKVxuXG4gIHQuaXMoaW5zdGFuY2UucHJvcDEsICdfX2RlZmF1bHRfXycpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCBvbmUgcHJvcGVydHkgd2l0aCBkZWZhdWx0IHZhbHVlIGFuZCBvdGhlciB3aXRob3V0IGRlZmF1bHQsIHdoZW4gaXQgaXMgY3JlYXRlZCB3aXRob3V0IHN1Y2ggcHJvcGVydHksIHRoZW4gaXQgc2hvdWxkIHNldCB0aGUgZm9ybWVyIHRvIHRoZSBkZWZhdWx0IHZhbHVlJywgdCA9PiB7XG4gIGNvbnN0IHNjaGVtYSA9IHtcbiAgICBwcm9wMDoge30sXG4gICAgcHJvcDE6IHtcbiAgICAgIGRlZmF1bHQ6ICdfX2RlZmF1bHRfXydcbiAgICB9LFxuICAgIHByb3AyOiB7fVxuICB9XG5cbiAgY29uc3QgZW1wdHlEYXRhID0ge31cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KGVtcHR5RGF0YSlcblxuICB0LmlzKGluc3RhbmNlLnByb3AxLCAnX19kZWZhdWx0X18nKVxufSlcblxudGVzdCgnR2l2ZW4gZW50aXR5IHdpdGggb25lIHByb3BlcnR5IHdpdGggZGVmYXVsdCB2YWx1ZSwgd2hlbiBmYWN0b3J5IGlzIGNhbGxlZCB3aXRob3V0IHN1Y2ggcHJvcGVydHkgYW5kIHdpdGggYGlnbm9yZURlZmF1bHRzYCBvcHRpb24gc2V0IHRvIGB0cnVlYCwgdGhlbiBpdCBzaG91bGQgbm90IHNldCB0aGUgcHJvcGVydHkgdG8gdGhlIGRlZmF1bHQgdmFsdWUnLCB0ID0+IHtcbiAgY29uc3Qgc2NoZW1hID0ge1xuICAgIHByb3AxOiB7XG4gICAgICBkZWZhdWx0OiAnX19kZWZhdWx0X18nXG4gICAgfVxuICB9XG5cbiAgY29uc3QgZW1wdHlEYXRhID0ge31cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KGVtcHR5RGF0YSwgeyBpZ25vcmVEZWZhdWx0czogdHJ1ZSB9KVxuXG4gIHQuaXMoaW5zdGFuY2UucHJvcDEsIHVuZGVmaW5lZClcbn0pXG5cbnRlc3QoJ0dpdmVuIGVudGl0eSB3aXRoIGByZWFkT25seWAgcHJvcGVydHksIHdoZW4gdHJ5aW5nIHRvIHNldCBzdWNoIHByb3BlcnR5LCB0aGVuIGl0IHNob3VsZCB0aHJvdyBhbiBlcnJvcicsIHQgPT4ge1xuICBjb25zdCBzY2hlbWEgPSB7XG4gICAgcHJvcDE6IHtcbiAgICAgIHJlYWRPbmx5OiB0cnVlXG4gICAgfVxuICB9XG5cbiAgY29uc3QgdmFsaWREYXRhID0ge1xuICAgIHByb3AxOiAnX19pbml0aWFsX18nXG4gIH1cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KHZhbGlkRGF0YSlcblxuICBjb25zdCBlcnJvciA9IHQudGhyb3dzKCgpID0+IHtcbiAgICBpbnN0YW5jZS5wcm9wMSA9ICdfX25ld19fJ1xuICB9KVxuXG4gIHQuaXMoZXJyb3IubmFtZSwgJ1R5cGVFcnJvcicpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCB2YWxpZGF0aW9uIGFuZCB2YWxpZCBkYXRhLCB3aGVuIHZhbGlkYXRlIGlzIGNhbGxlZCwgdGhlbiBpdCBzaG91bGQgbm90IHRocm93IGFuZCByZXR1cm4gaXRzZWxmJywgdCA9PiB7XG4gIGNvbnN0IHNjaGVtYSA9IHtcbiAgICBwcm9wMToge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfVxuICB9XG5cbiAgY29uc3QgdmFsaWREYXRhID0ge1xuICAgIHByb3AxOiAnYSdcbiAgfVxuXG4gIGNvbnN0IGZhY3RvcnkgPSBmYWN0b3J5Rm9yKHNjaGVtYSlcblxuICBjb25zdCBpbnN0YW5jZSA9IGZhY3RvcnkodmFsaWREYXRhKVxuXG4gIGNvbnN0IHJlc3VsdCA9IGluc3RhbmNlLnZhbGlkYXRlKClcblxuICB0LmlzKHJlc3VsdCwgaW5zdGFuY2UpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCB2YWxpZGF0aW9uIGFuZCBpbnZhbGlkIGRhdGEsIHdoZW4gdmFsaWRhdGUgaXMgY2FsbGVkLCB0aGVuIGl0IHNob3VsZCB0aHJvdycsIHQgPT4ge1xuICBjb25zdCBzY2hlbWEgPSB7XG4gICAgcHJvcDE6IHtcbiAgICAgIHZhbGlkYXRvcjogdmFsaWRhdG9ycy5yZXF1aXJlZFN0cmluZ1xuICAgIH0sXG4gICAgcHJvcDI6IHtcbiAgICAgIHZhbGlkYXRvcjogdmFsaWRhdG9ycy5yZXF1aXJlZFN0cmluZ1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGludmFsaWREYXRhID0ge1xuICAgIHByb3AxOiAnYSdcbiAgfVxuXG4gIGNvbnN0IGZhY3RvcnkgPSBmYWN0b3J5Rm9yKHNjaGVtYSlcblxuICBjb25zdCBpbnN0YW5jZSA9IGZhY3RvcnkoaW52YWxpZERhdGEpXG5cbiAgY29uc3QgZXJyb3IgPSB0LnRocm93cygoKSA9PiB7IGluc3RhbmNlLnZhbGlkYXRlKCkgfSlcbiAgdC5pcyhlcnJvci5jb2RlLCAnRVJSX1ZBTElEQVRJT04nKVxuICB0LnRydWUoZXJyb3IuZGV0YWlscy5oYXNPd25Qcm9wZXJ0eSgncHJvcDInKSlcbn0pXG5cbnRlc3QoJ0dpdmVuIGVudGl0eSB3aXRoIGZhY3RvcnkgYW5kIHZhbGlkIGRhdGEsIHdoZW4gZmFjdG9yeSBpcyBjYWxsZWQsIHRoZW4gaXQgcmV0dXJuIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBwcm9wZXJ0eScsIHQgPT4ge1xuICBjb25zdCBzY2hlbWEgPSB7XG4gICAgcHJvcDE6IHtcbiAgICAgIGZhY3Rvcnk6IE51bWJlclxuICAgIH0sXG4gICAgcHJvcDI6IHtcbiAgICAgIGZhY3Rvcnk6IE51bWJlclxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHZhbGlkRGF0YSA9IHtcbiAgICBwcm9wMTogJzEwMDAnLFxuICAgIHByb3AyOiAxMDAxXG4gIH1cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KHZhbGlkRGF0YSlcblxuICB0LmRlZXBFcXVhbChpbnN0YW5jZS50b0pTT04oKSwgeyBwcm9wMTogMTAwMCwgcHJvcDI6IDEwMDEgfSlcbn0pXG5cbnRlc3QoJ0dpdmVuIGVudGl0eSB3aXRoIG5lc3RlZCBlbnRpdHkgYW5kIHZhbGlkIGRhdGEsIHdoZW4gdmFsaWRhdGUgaXMgY2FsbGVkLCB0aGVuIGl0IHNob3VsZCBub3QgdGhyb3cgYW5kIHJldHVybiBpdHNlbGYnLCB0ID0+IHtcbiAgY29uc3QgY2hpbGRTY2hlbWEgPSB7XG4gICAgY2hpbGRQcm9wMToge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfVxuICB9XG4gIGNvbnN0IGNoaWxkRmFjdG9yeSA9IGZhY3RvcnlGb3IoY2hpbGRTY2hlbWEpXG5cbiAgY29uc3QgcGFyZW50U2NoZW1hID0ge1xuICAgIGNoaWxkRW50aXR5OiB7XG4gICAgICB2YWxpZGF0b3I6IGRlZmF1bHRWYWxpZGF0b3JzLmRlbGVnYXRlKCksXG4gICAgICBmYWN0b3J5OiBjaGlsZEZhY3RvcnlcbiAgICB9XG4gIH1cbiAgY29uc3QgcGFyZW50RmFjdG9yeSA9IGZhY3RvcnlGb3IocGFyZW50U2NoZW1hKVxuXG4gIGNvbnN0IHZhbGlkRGF0YSA9IHtcbiAgICBjaGlsZEVudGl0eToge1xuICAgICAgY2hpbGRQcm9wMTogJ2EnXG4gICAgfVxuICB9XG5cbiAgY29uc3QgaW5zdGFuY2UgPSBwYXJlbnRGYWN0b3J5KHZhbGlkRGF0YSlcblxuICBjb25zdCByZXN1bHQgPSBpbnN0YW5jZS52YWxpZGF0ZSgpXG5cbiAgdC5pcyhyZXN1bHQsIGluc3RhbmNlKVxufSlcblxudGVzdCgnR2l2ZW4gZW50aXR5IHdpdGggbWlzc2luZyB2YWxpZGF0b3IgZm9yIHByaW1pdGl2ZSBwcm9wZXJ0aWVzLCB3aGVuIHZhbGlkYXRlIGlzIGNhbGxlZCwgdGhlbiBpdCBzaG91bGQgbm90IHRocm93ICBhbmQgcmV0dXJuIGl0c2VsZicsIHQgPT4ge1xuICBjb25zdCBzY2hlbWEgPSB7XG4gICAgcHJvcDE6IHt9LFxuICAgIHByb3AyOiB7fVxuICB9XG5cbiAgY29uc3QgZW1wdHlEYXRhID0ge31cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KGVtcHR5RGF0YSlcblxuICBjb25zdCByZXN1bHQgPSBpbnN0YW5jZS52YWxpZGF0ZSgpXG4gIHQuaXMocmVzdWx0LCBpbnN0YW5jZSlcbn0pXG5cbnRlc3QoJ0dpdmVuIGVudGl0eSB3aXRoIG1pc3NpbmcgdmFsaWRhdG9yIGZvciBuZXN0ZWQgZW50aXR5IHByb3BlcnR5IHdpdGggdmFsaWQgZGF0YSwgd2hlbiB2YWxpZGF0ZSBpcyBjYWxsZWQsIHRoZW4gaXQgc2hvdWxkIG5vdCB0aHJvdyBhbmQgcmV0dXJuIGl0c2VsZicsIHQgPT4ge1xuICBjb25zdCBjaGlsZFNjaGVtYSA9IHtcbiAgICBjaGlsZFByb3AxOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgIGNoaWxkUHJvcDI6IHtcbiAgICAgIHZhbGlkYXRvcjogdmFsaWRhdG9ycy5yZXF1aXJlZFN0cmluZ1xuICAgIH1cbiAgfVxuICBjb25zdCBjaGlsZEZhY3RvcnkgPSBmYWN0b3J5Rm9yKGNoaWxkU2NoZW1hKVxuXG4gIGNvbnN0IHBhcmVudFNjaGVtYSA9IHtcbiAgICBjaGlsZEVudGl0eToge1xuICAgICAgZmFjdG9yeTogY2hpbGRGYWN0b3J5XG4gICAgfVxuICB9XG4gIGNvbnN0IHBhcmVudEZhY3RvcnkgPSBmYWN0b3J5Rm9yKHBhcmVudFNjaGVtYSlcblxuICBjb25zdCB2YWxpZERhdGEgPSB7XG4gICAgY2hpbGRFbnRpdHk6IHtcbiAgICAgIGNoaWxkUHJvcDE6ICdhJyxcbiAgICAgIGNoaWxkUHJvcDI6ICdhJ1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGluc3RhbmNlID0gcGFyZW50RmFjdG9yeSh2YWxpZERhdGEpXG5cbiAgY29uc3QgcmVzdWx0ID0gaW5zdGFuY2UudmFsaWRhdGUoKVxuICB0LmlzKHJlc3VsdCwgaW5zdGFuY2UpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCBtaXNzaW5nIHZhbGlkYXRvciBmb3IgbmVzdGVkIGVudGl0eSBwcm9wZXJ0eSB3aXRoIGludmFsaWREYXRhLCB3aGVuIHZhbGlkYXRlIGlzIGNhbGxlZCwgdGhlbiBpdCBzaG91bGQgbm90IHRocm93IGFuZCByZXR1cm4gaXRzZWxmJywgdCA9PiB7XG4gIGNvbnN0IGNoaWxkU2NoZW1hID0ge1xuICAgIGNoaWxkUHJvcDE6IHtcbiAgICAgIHZhbGlkYXRvcjogdmFsaWRhdG9ycy5yZXF1aXJlZFN0cmluZ1xuICAgIH0sXG4gICAgY2hpbGRQcm9wMjoge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfVxuICB9XG4gIGNvbnN0IGNoaWxkRmFjdG9yeSA9IGZhY3RvcnlGb3IoY2hpbGRTY2hlbWEpXG5cbiAgY29uc3QgcGFyZW50U2NoZW1hID0ge1xuICAgIGNoaWxkRW50aXR5OiB7XG4gICAgICBmYWN0b3J5OiBjaGlsZEZhY3RvcnlcbiAgICB9XG4gIH1cbiAgY29uc3QgcGFyZW50RmFjdG9yeSA9IGZhY3RvcnlGb3IocGFyZW50U2NoZW1hKVxuXG4gIGNvbnN0IGludmFsaWREYXRhID0ge1xuICAgIGNoaWxkRW50aXR5OiB7XG4gICAgICBjaGlsZFByb3AxOiAnYSdcbiAgICB9XG4gIH1cblxuICBjb25zdCBpbnN0YW5jZSA9IHBhcmVudEZhY3RvcnkoaW52YWxpZERhdGEpXG5cbiAgY29uc3QgcmVzdWx0ID0gaW5zdGFuY2UudmFsaWRhdGUoKVxuICB0LmlzKHJlc3VsdCwgaW5zdGFuY2UpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCBuZXN0ZWQgZW50aXR5IHdpdGggYGRlbGVnYXRlYCB2YWxpZGF0b3IgYW5kIGludmFsaWQgZGF0YSwgd2hlbiB2YWxpZGF0ZSBpcyBjYWxsZWQsIHRoZW4gaXQgc2hvdWxkIHRocm93JywgdCA9PiB7XG4gIGNvbnN0IGNoaWxkU2NoZW1hID0ge1xuICAgIGNoaWxkUHJvcDE6IHtcbiAgICAgIHZhbGlkYXRvcjogdmFsaWRhdG9ycy5yZXF1aXJlZFN0cmluZ1xuICAgIH0sXG4gICAgY2hpbGRQcm9wMjoge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfVxuICB9XG4gIGNvbnN0IGNoaWxkRmFjdG9yeSA9IGZhY3RvcnlGb3IoY2hpbGRTY2hlbWEpXG5cbiAgY29uc3QgcGFyZW50U2NoZW1hID0ge1xuICAgIGNoaWxkRW50aXR5OiB7XG4gICAgICB2YWxpZGF0b3I6IGRlZmF1bHRWYWxpZGF0b3JzLmRlbGVnYXRlKCksXG4gICAgICBmYWN0b3J5OiBjaGlsZEZhY3RvcnlcbiAgICB9XG4gIH1cbiAgY29uc3QgcGFyZW50RmFjdG9yeSA9IGZhY3RvcnlGb3IocGFyZW50U2NoZW1hKVxuXG4gIGNvbnN0IGludmFsaWREYXRhID0ge1xuICAgIGNoaWxkRW50aXR5OiB7XG4gICAgICBjaGlsZFByb3AxOiAnYSdcbiAgICB9XG4gIH1cblxuICBjb25zdCBpbnN0YW5jZSA9IHBhcmVudEZhY3RvcnkoaW52YWxpZERhdGEpXG5cbiAgY29uc3QgZXJyb3IgPSB0LnRocm93cygoKSA9PiBpbnN0YW5jZS52YWxpZGF0ZSgpKVxuICB0LmlzKGVycm9yLmNvZGUsICdFUlJfVkFMSURBVElPTicpXG4gIHQudHJ1ZShlcnJvci5kZXRhaWxzLmhhc093blByb3BlcnR5KCdjaGlsZEVudGl0eScpKVxuICB0LnRydWUoZXJyb3IuZGV0YWlscy5jaGlsZEVudGl0eS5oYXNPd25Qcm9wZXJ0eSgnY2hpbGRQcm9wMicpKVxufSlcblxudGVzdCgnR2l2ZW4gZW50aXR5IHdpdGggbmVzdGVkIGVudGl0eSB3aXRoIGBkZWxlZ2F0ZWAgdmFsaWRhdG9yIHdpdGggYHJlcXVpcmVkYCBvcHRpb24gPSB0cnVlIGFuZCBkYXRhIG1pc3NpbmcgZm9yIG5lc3RlZCwgd2hlbiB2YWxpZGF0ZSBpcyBjYWxsZWQsIHRoZW4gaXQgc2hvdWxkIHRocm93JywgdCA9PiB7XG4gIGNvbnN0IGNoaWxkU2NoZW1hID0ge1xuICAgIGNoaWxkUHJvcDE6IHtcbiAgICAgIHZhbGlkYXRvcjogdmFsaWRhdG9ycy5yZXF1aXJlZFN0cmluZ1xuICAgIH0sXG4gICAgY2hpbGRQcm9wMjoge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfVxuICB9XG4gIGNvbnN0IGNoaWxkRmFjdG9yeSA9IGZhY3RvcnlGb3IoY2hpbGRTY2hlbWEpXG5cbiAgY29uc3QgcGFyZW50U2NoZW1hID0ge1xuICAgIGNoaWxkRW50aXR5OiB7XG4gICAgICB2YWxpZGF0b3I6IGRlZmF1bHRWYWxpZGF0b3JzLmRlbGVnYXRlKHsgcmVxdWlyZWQ6IHRydWUgfSksXG4gICAgICBmYWN0b3J5OiBjaGlsZEZhY3RvcnlcbiAgICB9XG4gIH1cbiAgY29uc3QgcGFyZW50RmFjdG9yeSA9IGZhY3RvcnlGb3IocGFyZW50U2NoZW1hKVxuXG4gIGNvbnN0IGludmFsaWREYXRhID0ge31cblxuICBjb25zdCBpbnN0YW5jZSA9IHBhcmVudEZhY3RvcnkoaW52YWxpZERhdGEpXG5cbiAgY29uc3QgZXJyb3IgPSB0LnRocm93cygoKSA9PiBpbnN0YW5jZS52YWxpZGF0ZSgpKVxuXG4gIHQuaXMoZXJyb3IuY29kZSwgJ0VSUl9WQUxJREFUSU9OJylcbiAgdC5ub3RSZWdleChlcnJvci5tZXNzYWdlLCAvY2Fubm90IHJlYWQgcHJvcGVydHkgJ3ZhbGlkYXRlJyBvZiB1bmRlZmluZWQvaSlcbiAgdC50cnVlKGVycm9yLmRldGFpbHMuaGFzT3duUHJvcGVydHkoJ2NoaWxkRW50aXR5JykpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCBuZXN0ZWQgZW50aXR5IHdpdGggYGRlbGVnYXRlYCB2YWxpZGF0b3Igd2l0aCBjb250ZXh0IGFuZCBgcmVxdWlyZWRgIG9wdGlvbiA9IHRydWUgYW5kIGRhdGEgbWlzc2luZyBmb3IgbmVzdGVkLCB3aGVuIHZhbGlkYXRlIGlzIGNhbGxlZCwgdGhlbiBpdCBzaG91bGQgdGhyb3cnLCB0ID0+IHtcbiAgY29uc3QgY2hpbGRTY2hlbWEgPSB7XG4gICAgY2hpbGRQcm9wMToge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfSxcbiAgICBjaGlsZFByb3AyOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgICRjb250ZXh0czoge1xuICAgICAgbXlDb250ZXh0OiB7fVxuICAgIH1cbiAgfVxuICBjb25zdCBjaGlsZEZhY3RvcnkgPSBmYWN0b3J5Rm9yKGNoaWxkU2NoZW1hKVxuXG4gIGNvbnN0IHBhcmVudFNjaGVtYSA9IHtcbiAgICBjaGlsZEVudGl0eToge1xuICAgICAgdmFsaWRhdG9yOiBkZWZhdWx0VmFsaWRhdG9ycy5kZWxlZ2F0ZSgnbXlDb250ZXh0JywgeyByZXF1aXJlZDogdHJ1ZSB9KSxcbiAgICAgIGZhY3Rvcnk6IGNoaWxkRmFjdG9yeVxuICAgIH1cbiAgfVxuICBjb25zdCBwYXJlbnRGYWN0b3J5ID0gZmFjdG9yeUZvcihwYXJlbnRTY2hlbWEpXG5cbiAgY29uc3QgaW52YWxpZERhdGEgPSB7fVxuXG4gIGNvbnN0IGluc3RhbmNlID0gcGFyZW50RmFjdG9yeShpbnZhbGlkRGF0YSlcblxuICBjb25zdCBlcnJvciA9IHQudGhyb3dzKCgpID0+IGluc3RhbmNlLnZhbGlkYXRlKCkpXG5cbiAgdC5pcyhlcnJvci5jb2RlLCAnRVJSX1ZBTElEQVRJT04nKVxuICB0Lm5vdFJlZ2V4KGVycm9yLm1lc3NhZ2UsIC9jYW5ub3QgcmVhZCBwcm9wZXJ0eSAndmFsaWRhdGUnIG9mIHVuZGVmaW5lZC9pKVxuICB0LnRydWUoZXJyb3IuZGV0YWlscy5oYXNPd25Qcm9wZXJ0eSgnY2hpbGRFbnRpdHknKSlcbn0pXG5cbnRlc3QoJ0dpdmVuIGVudGl0eSB3aXRoIG5lc3RlZCBlbnRpdHkgd2l0aCBgZGVsZWdhdGVgIHZhbGlkYXRvciBmb3IgYSBnaXZlbiBjb250ZXh0IGFuZCB2YWxpZCBkYXRhIGZvciBzdWNoIGNvbnRleHQsIHdoZW4gdmFsaWRhdGUgaXMgY2FsbGVkLCB0aGVuIGl0IHNob3VsZCBub3QgdGhyb3cgYW5kIHJldHVybiBpdHNlbGYnLCB0ID0+IHtcbiAgY29uc3QgY2hpbGRTY2hlbWEgPSB7XG4gICAgY2hpbGRQcm9wMToge1xuICAgICAgdmFsaWRhdG9yOiB2YWxpZGF0b3JzLnJlcXVpcmVkU3RyaW5nXG4gICAgfSxcbiAgICBjaGlsZFByb3AyOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgICRjb250ZXh0czoge1xuICAgICAgbXlDb250ZXh0OiB7XG4gICAgICAgICRleGNsdWRlOiBbJ2NoaWxkUHJvcDInXVxuICAgICAgfVxuICAgIH1cbiAgfVxuICBjb25zdCBjaGlsZEZhY3RvcnkgPSBmYWN0b3J5Rm9yKGNoaWxkU2NoZW1hKVxuXG4gIGNvbnN0IHBhcmVudFNjaGVtYSA9IHtcbiAgICBjaGlsZEVudGl0eToge1xuICAgICAgdmFsaWRhdG9yOiBkZWZhdWx0VmFsaWRhdG9ycy5kZWxlZ2F0ZSgnbXlDb250ZXh0JyksXG4gICAgICBmYWN0b3J5OiBjaGlsZEZhY3RvcnlcbiAgICB9XG4gIH1cbiAgY29uc3QgcGFyZW50RmFjdG9yeSA9IGZhY3RvcnlGb3IocGFyZW50U2NoZW1hKVxuXG4gIGNvbnN0IHZhbGlkRGF0YUZvckNvbnRleHQgPSB7XG4gICAgY2hpbGRFbnRpdHk6IHtcbiAgICAgIGNoaWxkUHJvcDE6ICdhJ1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGluc3RhbmNlID0gcGFyZW50RmFjdG9yeSh2YWxpZERhdGFGb3JDb250ZXh0KVxuXG4gIHQuaXMoaW5zdGFuY2UudmFsaWRhdGUoKSwgaW5zdGFuY2UpXG59KVxuXG50ZXN0KCdHaXZlbiBlbnRpdHkgd2l0aCBjb250ZXh0IHRoYXQgZXhjbHVkZXMgYHByb3AyYCBhbmQgaW52YWxpZCBkYXRhIGBwcm9wMmAsIHdoZW4gdmFsaWRhdGUgaXMgY2FsbGVkIHdpdGggc3VjaCBjb250ZXh0LCB0aGVuIGl0IHNob3VsZCBub3QgdGhyb3cgYW5kIHJldHVybiBpdHNlbGYnLCB0ID0+IHtcbiAgY29uc3Qgc2NoZW1hID0ge1xuICAgIHByb3AxOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgIHByb3AyOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgICRjb250ZXh0czoge1xuICAgICAgbXlDb250ZXh0OiB7XG4gICAgICAgICRleGNsdWRlOiBbJ3Byb3AyJ11cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBpbnZhbGlkRGF0YSA9IHtcbiAgICBwcm9wMTogJ2EnXG4gIH1cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KGludmFsaWREYXRhKVxuXG4gIGNvbnN0IHJlc3VsdCA9IGluc3RhbmNlLnZhbGlkYXRlKCdteUNvbnRleHQnKVxuXG4gIHQuaXMocmVzdWx0LCBpbnN0YW5jZSlcbn0pXG5cbnRlc3QoJ0dpdmVuIGVudGl0eSB3aXRoIGNvbnRleHQgdGhhdCBtb2RpZmllcyBgcHJvcDJgIGFuZCB2YWxpZCBkYXRhIGZvciBzdWNoIGNvbnRleHQsIHdoZW4gdmFsaWRhdGUgaXMgY2FsbGVkIHdpdGggc3VjaCBjb250ZXh0LCB0aGVuIGl0IHNob3VsZCB1c2UgdGhlIHZhbGlkYXRvciBmcm9tIHRoZSBjb250ZXh0IGRlZmluaXRpb24nLCB0ID0+IHtcbiAgY29uc3Qgc2NoZW1hID0ge1xuICAgIHByb3AxOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgIHByb3AyOiB7XG4gICAgICB2YWxpZGF0b3I6IHZhbGlkYXRvcnMucmVxdWlyZWRTdHJpbmdcbiAgICB9LFxuICAgICRjb250ZXh0czoge1xuICAgICAgbXlDb250ZXh0OiB7XG4gICAgICAgICRtb2RpZnk6IHtcbiAgICAgICAgICBwcm9wMjogdmFsaWRhdG9ycy5yZXF1aXJlZE51bWJlclxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3QgdmFsaWREYXRhRm9yQ29udGV4dCA9IHtcbiAgICBwcm9wMTogJ2EnLFxuICAgIHByb3AyOiAxXG4gIH1cblxuICBjb25zdCBmYWN0b3J5ID0gZmFjdG9yeUZvcihzY2hlbWEpXG5cbiAgY29uc3QgaW5zdGFuY2UgPSBmYWN0b3J5KHZhbGlkRGF0YUZvckNvbnRleHQpXG5cbiAgY29uc3QgcmVzdWx0ID0gaW5zdGFuY2UudmFsaWRhdGUoJ215Q29udGV4dCcpXG5cbiAgdC5pcyhyZXN1bHQsIGluc3RhbmNlKVxufSlcblxudGVzdCgnR2l2ZW4gZW50aXR5IHdpdGggY29udGV4dCB0aGF0IGV4Y2x1ZGVzIGBwcm9wMmAsIHdoZW4gYHRvSlNPTigpYCBpcyBjYWxsZWQgd2l0aCBzdWNoIGNvbnRleHQsIHRoZW4gaXQgc2hvdWxkIG9taXQgYHByb3AyYCBmcm9tIHRoZSByZXN1bHQnLCB0ID0+IHtcbiAgY29uc3Qgc2NoZW1hID0ge1xuICAgIHByb3AxOiB7fSxcbiAgICBwcm9wMjoge30sXG4gICAgJGNvbnRleHRzOiB7XG4gICAgICBteUNvbnRleHQ6IHtcbiAgICAgICAgJGV4Y2x1ZGU6IFsncHJvcDInXVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHZhbGlkRGF0YSA9IHtcbiAgICBwcm9wMTogJ2EnLFxuICAgIHByb3AyOiAnYidcbiAgfVxuXG4gIGNvbnN0IGZhY3RvcnkgPSBmYWN0b3J5Rm9yKHNjaGVtYSlcblxuICBjb25zdCBpbnN0YW5jZSA9IGZhY3RvcnkodmFsaWRE