mage-validator
Version:
Validation utility for MAGE user commands & topics (TypeScript)
407 lines • 40.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const classTransformer = require("class-transformer");
const classValidator = require("class-validator");
const isObject = require("isobject");
const errors_1 = require("../errors");
/**
* Validated topic
*
* Please note that you should import the default
* of this module, not this class directly.
*
* Good:
*
* ```typescript
* import ValidatedTopic from 'mage-validator'
* ```
*
* Bad:
*
* ```typescript
* import { ValidatedTopic } from 'mage-validator'
* ```
*
* While the second line will work, it will provide you with
* less type safety than the first import example.
*
* @export
* @abstract
* @class ValidatedTopic
*/
class ValidatedTopic {
/**
* Creates an instance of ValidatedTopic.
*
* @param {mage.core.IState} state
*
* @memberof ValidatedTopic
*/
constructor(state) {
this.setTopic(this.constructor.name);
if (state) {
this.setState(state);
}
}
/**
* Return the current class name
*
* @static
* @returns
*
* @memberof ValidatedTopic
*/
static getClassName() {
/* istanbul ignore next */
if (!this._className) {
return this.toString().split('(' || /s+/)[0].split(' ' || /s+/)[1];
}
return this._className;
}
/**
* Explicitly set the name of this class
*
* @static
* @param {string} name
*
* @memberof ValidatedTopic
*/
static setClassName(name) {
this._className = name;
}
/**
* Create an instance from a generic object
*
* @static
* @param {mage.core.IState} state
* @param {*} data
* @returns
*
* @memberof ValidatedTopic
*/
static async create(state, index, data) {
let instance;
if (data) {
if (!isObject(data)) {
throw new Error(`Received data is not an object (received ${JSON.stringify(data)})`);
}
instance = classTransformer.plainToClass(this, data);
}
else {
instance = new this();
}
instance.setTopic(this.getClassName());
instance.setState(state);
await instance.setIndex(index);
return instance;
}
/**
* Utility method used to promisify archivist calls
*
* @static
* @param {*} state
* @param {*} method
* @param {any[]} args
* @param {Function} run
* @returns
*
* @memberof ValidatedTopic
*/
static async execute(state, method, args, run) {
return new Promise((resolve, reject) => {
state.archivist[method](...args, (error, data) => {
if (error) {
return reject(error);
}
resolve(run(data));
});
});
}
/**
* Get a topic instance from backend vault(s)
*
* Mostly a wrapper around state.archivist.get. Note that
* instead of using the `optional` option directly with this call,
* you should consider using `tryGet` instead, which will trigger a
* compile error if you do not check for an undefined return value.
*
* @static
* @param {mage.core.IState} state
* @param {archivist.IArchivistIndex} index
* @param {archivist.IArchivistGetOptions} [options]
* @returns
*
* @memberof ValidatedTopic
*/
static async get(state, index, options) {
const topicName = this.getClassName();
return this.execute(state, 'get', [
topicName,
index,
options
], async (data) => {
// If optional: true, and no data was found
if (options && options.optional && !data) {
return undefined;
}
return this.create(state, index, data);
});
}
/**
* Try to get a topic instance from backend vault(s)
*
* Same as `get`, but is also states that `undefined' might be returned instead.
* You should consider using this method instead of calling `get` directly
* with the `optional: true` option.
*
* @static
* @param {mage.core.IState} state
* @param {archivist.IArchivistIndex} index
* @param {archivist.IArchivistGetOptions} [options]
* @returns
*
* @memberof ValidatedTopic
*/
static async tryGet(state, index, options) {
if (!options) {
options = {};
}
options.optional = true;
return this.get(state, index, options);
}
/**
* Get instances from backend vault(s)
*
* Mostly a wrapper around state.archivist.mget.
*
* @static
* @param {mage.core.IState} state
* @param {archivist.IArchivistQuery[]} queries
* @param {archivist.IArchivistGetOptions} [options]
* @returns
*
* @memberof ValidatedTopic
*/
static async mget(state, indexes, options) {
const topic = this.getClassName();
const queries = indexes.map((index) => ({ topic, index }));
return this.execute(state, 'mget', [
queries,
options
], async (list) => {
const instances = [];
for (const [i, data] of list.entries()) {
if (!data) {
continue;
}
const index = queries[i].index;
const instance = await this.create(state, index, data);
instances.push(instance);
}
return instances;
});
}
//
// Todo:
//
// public static async mget(state: mage.core.IState, queries: archivist.INamedArchivistQuery, options?: archivist.IArchivistGetOptions) {
// return new Promise((resolve, reject) => {
// state.archivist.mget(queries, options, async (error, list) => {
// if (error) {
// return reject(error)
// }
// const instances = Object.keys(list).reduce((instances, name) => {
// if (list[name]) {
// instances[name] = this.create(state, queries[name], list[name])
// }
// return instances
// }, {})
// resolve(instances)
// })
// })
// }
/**
* List all keys
*
* @static
* @param {mage.core.IState} state
* @param {archivist.IArchivistIndex} partialIndex
* @param {archivist.IArchivistGetOptions} [options]
* @returns
*
* @memberof ValidatedTopic
*/
static async list(state, partialIndex, options) {
const topicName = this.getClassName();
return this.execute(state, 'list', [
topicName,
partialIndex,
options,
], (indexes) => indexes);
}
/**
* Query data by partial index
*
* Essentially wraps state.archivist.list, then fetches the data
* for each keys using state.archivist.mget.
*
* @static
* @param {mage.core.IState} state
* @param {archivist.IArchivistIndex} partialIndex
* @param {archivist.IArchivistGetOptions} [options]
* @returns
*
* @memberof ValidatedTopic
*/
static async query(state, partialIndex, options) {
const topicName = this.getClassName();
return this.execute(state, 'list', [
topicName,
partialIndex,
options
], async (indexes) => {
return this.mget(state, indexes, options);
});
}
/**
* Get the topic for this instance
*
* @memberof ValidatedTopic
*/
getTopic() {
return this._topic;
}
/**
* Set the topic name for this instance
*
* @param {string} topicName
*
* @memberof ValidatedTopic
*/
setTopic(topicName) {
Object.defineProperty(this, '_topic', {
value: topicName,
configurable: true
});
}
/**
* Get the topic of that instance
*
* Should always return the class name of the instance.
*
* @returns
*
* @memberof ValidatedTopic
*/
getIndex() {
return this._index;
}
/**
* Set the index of this topic instance
*
* @param {archivist.IArchivistIndex} index
*
* @memberof ValidatedTopic
*/
async setIndex(indexData) {
const Class = this.constructor;
const Index = Class.indexType;
const index = new Index();
for (const field of Class.index) {
index[field] = indexData[field];
}
const errors = await classValidator.validate(index);
if (errors.length > 0) {
throw new errors_1.ValidationError('Index validation failed', 'server', {
topic: this.getTopic(),
index: this.getIndex()
}, errors);
}
Object.defineProperty(this, '_index', {
value: index,
configurable: true
});
}
/**
* Retrieve the state object attached to the instance
*/
getState() {
return this._state;
}
/**
* Set the state this topic instance will be using.
*/
setState(state) {
Object.defineProperty(this, '_state', {
value: state,
configurable: true
});
}
/**
* Retrieve the actual data for this instance
*
* This should essentially be the same as simply accessing data on the
* instance itself.
*/
getData() {
return this;
}
/**
* Record an add operation on the instance's state
*
* Essentially a wrapper for state.archivist.add
*/
async add(mediaType, encoding, expirationTime) {
await this.validate('Validation failed on add');
return this.getState().archivist.add(this.getTopic(), this.getIndex(), this.getData(), mediaType, encoding, expirationTime);
}
/**
* Record a set operation on the instance's state
*
* Essentially a wrapper for state.archivist.set.
*/
async set(mediaType, encoding, expirationTime) {
await this.validate('Validation failed on set');
return this.getState().archivist.set(this.getTopic(), this.getIndex(), this.getData(), mediaType, encoding, expirationTime);
}
/**
* Record a touch operation on the instance's state
*
* Essentially a wrapper for state.archivist.touch.
*/
async touch(expirationTime) {
await this.validate('Validation failed on touch');
return this.getState().archivist.touch(this.getTopic(), this.getIndex(), expirationTime);
}
/**
* Record a delete operation on the instance's state
*/
del() {
return this.getState().archivist.del(this.getTopic(), this.getIndex());
}
/**
* Validate the current instance
*/
async validate(errorMessage, code) {
const errors = await classValidator.validate(this);
if (errors.length > 0) {
this.raiseValidationError(errors, errorMessage, code);
}
}
/**
* Throw a ValidateError including relevant details
*/
raiseValidationError(errors, errorMessage, code) {
const state = this.getState();
throw new errors_1.ValidationError(errorMessage || 'Validation failed', code || 'server', {
actorId: state.actorId,
userCommand: state.description,
topic: this.getTopic(),
index: this.getIndex()
}, errors);
}
}
ValidatedTopic.mediaType = 'application/json';
ValidatedTopic.vaults = {};
exports.default = ValidatedTopic;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmFsaWRhdGVkVG9waWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xhc3Nlcy9WYWxpZGF0ZWRUb3BpYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHNEQUFxRDtBQUNyRCxrREFBaUQ7QUFDakQscUNBQXFDO0FBS3JDLHNDQUEyQztBQThEM0M7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdCRztBQUNIO0lBcVNFOzs7Ozs7T0FNRztJQUNILFlBQVksS0FBd0I7UUFDbEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFBO1FBRXBDLElBQUksS0FBSyxFQUFFO1lBQ1QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtTQUNyQjtJQUNILENBQUM7SUExU0Q7Ozs7Ozs7T0FPRztJQUNJLE1BQU0sQ0FBQyxZQUFZO1FBQ3hCLDBCQUEwQjtRQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNwQixPQUFPLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxLQUFLLENBQUUsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBRSxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7U0FDckU7UUFFRCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUE7SUFDeEIsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxNQUFNLENBQUMsWUFBWSxDQUFDLElBQVk7UUFDckMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUE7SUFDeEIsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNJLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUV4QixLQUF1QixFQUN2QixLQUFRLEVBQ1IsSUFBbUI7UUFFbkIsSUFBSSxRQUFRLENBQUE7UUFFWixJQUFJLElBQUksRUFBRTtZQUNSLElBQUksQ0FBQyxRQUFRLENB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RUFBRSxJQUFJLENBQUMsQ0FBQTtTQUN0RDtJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLG9CQUFvQixDQUFDLE1BQWEsRUFBRSxZQUFxQixFQUFFLElBQWE7UUFDN0UsTUFBTSxLQUFLLEdBQVMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFBO1FBRW5DLE1BQU0sSUFBSSx3QkFBZSxDQUFDLFlBQVksSUFBSSxtQkFBbUIsRUFBRSxJQUFJLElBQUksUUFBUSxFQUFFO1lBQy9FLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztZQUN0QixXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7WUFDOUIsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDdEIsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUU7U0FDdkIsRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUNaLENBQUM7O0FBNWNzQix3QkFBUyxHQUFXLGtCQUFrQixDQUFBO0FBR3RDLHFCQUFNLEdBQUcsRUFBRSxDQUFBO0FBSnBDLGlDQThjQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNsYXNzVHJhbnNmb3JtZXIgZnJvbSAnY2xhc3MtdHJhbnNmb3JtZXInXG5pbXBvcnQgKiBhcyBjbGFzc1ZhbGlkYXRvciBmcm9tICdjbGFzcy12YWxpZGF0b3InXG5pbXBvcnQgaXNPYmplY3QgPSByZXF1aXJlKCdpc29iamVjdCcpXG5cbmltcG9ydCB7IGFyY2hpdmlzdCB9IGZyb20gJ21hZ2UnXG5pbXBvcnQgKiBhcyBtYWdlIGZyb20gJ21hZ2UnXG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gJy4uL2Vycm9ycydcblxuLy8gdHNsaW50OmRpc2FibGU6Y29tcGxldGVkLWRvY3NcbnR5cGUgS2V5ID0gc3RyaW5nIHwgbnVtYmVyIHwgc3ltYm9sXG5cbmV4cG9ydCB0eXBlIERpZmY8VCBleHRlbmRzIEtleSwgVSBleHRlbmRzIEtleT4gPSAoe1tQIGluIFRdOiBQIH0gJiB7W1AgaW4gVV06IG5ldmVyIH0gJiB7IFt4OiBzdHJpbmddOiBuZXZlciB9KVtUXVxuXG4vLyB0c2xpbnQ6ZGlzYWJsZTpjb21wbGV0ZWQtZG9jc1xuZXhwb3J0IHR5cGUgT21pdDxULCBLIGV4dGVuZHMga2V5b2YgVD4gPSBQaWNrPFBhcnRpYWw8VD4sIERpZmY8a2V5b2YgVCwgSz4+XG5cbi8qKlxuICogQW5vbnltb3VzIG9iamVjdCByZXByZXNlbnRhdGlvbiBvZiBhIHZhbGlkYXRlZCB0b3BpY1xuICpcbiAqIEdlbmVyYWxseSBwYXNzZWQgdG8gVG9waWMuY3JlYXRlKClcbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNEYXRhPFQgZXh0ZW5kcyBWYWxpZGF0ZWRUb3BpYz4gPSBPbWl0PFQsIGtleW9mIFZhbGlkYXRlZFRvcGljPlxuLyoqXG4gKiBQYXJ0aWFsIGluZGV4IHR5cGVcbiAqL1xuZXhwb3J0IHR5cGUgUGFydGlhbEluZGV4PEk+ID0ge1xuICBbSyBpbiBrZXlvZiBJXT86IHN0cmluZ1xufVxuXG4vKipcbiAqIFRoZSBJU3RhdGljVGhpcyBpbnRlcmZhY2UgaXMgcmVxdWlyZWRcbiAqIGZvciB1cyB0byBiZSBhYmxlIHRvIGNyZWF0ZSBzdGF0aWMgZmFjdG9yeSBmdW5jdGlvbnNcbiAqIHRoYXQgcmV0dXJuIGEgcHJvcGVybHkgdHlwZWQgb3V0cHV0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElTdGF0aWNUaGlzPEksIFQ+IHtcbiAgLy8gVG9kbzogYW55IHNob3VsZCBiZSBJIVxuICBpbmRleFR5cGU6IHsgbmV3KCk6IGFueSB9LFxuXG4gIG5ldyAoKTogVCxcblxuICBnZXRDbGFzc05hbWUoKTogc3RyaW5nLFxuXG4gIGV4ZWN1dGU8SSwgVCwgUj4oXG4gICAgdGhpczogSVN0YXRpY1RoaXM8SSwgVD4sXG4gICAgc3RhdGU6IGFueSxcbiAgICBtZXRob2Q6IGFueSxcbiAgICBhcmdzOiBhbnlbXSxcbiAgICBydW46IChkYXRhOiBhbnkpID0+IGFueSk6IFByb21pc2U8Uj4sXG5cbiAgY3JlYXRlPFQgZXh0ZW5kcyBWYWxpZGF0ZWRUb3BpYz4oXG4gICAgdGhpczogSVN0YXRpY1RoaXM8SSwgVD4sXG4gICAgc3RhdGU6IG1hZ2UuY29yZS5JU3RhdGUsXG4gICAgaW5kZXg6IEksXG4gICAgZGF0YT86IGFueSk6IFByb21pc2U8VD4sXG5cbiAgZ2V0PFQgZXh0ZW5kcyBWYWxpZGF0ZWRUb3BpYz4oXG4gICAgdGhpczogSVN0YXRpY1RoaXM8SSwgVD4sXG4gICAgc3RhdGU6IG1hZ2UuY29yZS5JU3RhdGUsXG4gICAgaW5kZXg6IEksXG4gICAgb3B0aW9ucz86IGFyY2hpdmlzdC5JQXJjaGl2aXN0R2V0T3B0aW9ucyk6IFByb21pc2U8VD5cblxuICBtZ2V0PFQgZXh0ZW5kcyBWYWxpZGF0ZWRUb3BpYz4oXG4gICAgdGhpczogSVN0YXRpY1RoaXM8SSwgVD4sXG4gICAgc3RhdGU6IG1hZ2UuY29yZS5JU3RhdGUsXG4gICAgaW5kZXhlczogSVtdLFxuICAgIG9wdGlvbnM/OiBhcmNoaXZpc3QuSUFyY2hpdmlzdEdldE9wdGlvbnMpOiBQcm9taXNlPFRbXT5cbn1cblxuLyoqXG4gKiBWYWxpZGF0ZWQgdG9waWNcbiAqXG4gKiBQbGVhc2Ugbm90ZSB0aGF0IHlvdSBzaG91bGQgaW1wb3J0IHRoZSBkZWZhdWx0XG4gKiBvZiB0aGlzIG1vZHVsZSwgbm90IHRoaXMgY2xhc3MgZGlyZWN0bHkuXG4gKlxuICogR29vZDpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgVmFsaWRhdGVkVG9waWMgZnJvbSAnbWFnZS12YWxpZGF0b3InXG4gKiBgYGBcbiAqXG4gKiBCYWQ6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgVmFsaWRhdGVkVG9waWMgfSBmcm9tICdtYWdlLXZhbGlkYXRvcidcbiAqIGBgYFxuICpcbiAqIFdoaWxlIHRoZSBzZWNvbmQgbGluZSB3aWxsIHdvcmssIGl0IHdpbGwgcHJvdmlkZSB5b3Ugd2l0aFxuICogbGVzcyB0eXBlIHNhZmV0eSB0aGFuIHRoZSBmaXJzdCBpbXBvcnQgZXhhbXBsZS5cbiAqXG4gKiBAZXhwb3J0XG4gKiBAYWJzdHJhY3RcbiAqIEBjbGFzcyBWYWxpZGF0ZWRUb3BpY1xuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWYWxpZGF0ZWRUb3BpYyB7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgbWVkaWFUeXBlOiBzdHJpbmcgPSAnYXBwbGljYXRpb24vanNvbidcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBpbmRleDogc3RyaW5nW11cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBpbmRleFR5cGU6IGFueVxuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IHZhdWx0cyA9IHt9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgX2NsYXNzTmFtZTogc3RyaW5nXG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgY3VycmVudCBjbGFzcyBuYW1lXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQHJldHVybnNcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldENsYXNzTmFtZSgpOiBzdHJpbmcge1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgaWYgKCF0aGlzLl9jbGFzc05hbWUpIHtcbiAgICAgIHJldHVybiB0aGlzLnRvU3RyaW5nKCkuc3BsaXQgKCcoJyB8fCAvcysvKVswXS5zcGxpdCAoJyAnIHx8IC9zKy8pWzFdXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuX2NsYXNzTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIEV4cGxpY2l0bHkgc2V0IHRoZSBuYW1lIG9mIHRoaXMgY2xhc3NcbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZVxuICAgKlxuICAgKiBAbWVtYmVyb2YgVmFsaWRhdGVkVG9waWNcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc2V0Q2xhc3NOYW1lKG5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuX2NsYXNzTmFtZSA9IG5hbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYW4gaW5zdGFuY2UgZnJvbSBhIGdlbmVyaWMgb2JqZWN0XG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQHBhcmFtIHttYWdlLmNvcmUuSVN0YXRlfSBzdGF0ZVxuICAgKiBAcGFyYW0geyp9IGRhdGFcbiAgICogQHJldHVybnNcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIGNyZWF0ZTxJIGV4dGVuZHMgYXJjaGl2aXN0LklBcmNoaXZpc3RJbmRleCwgVCBleHRlbmRzIFZhbGlkYXRlZFRvcGljPihcbiAgICB0aGlzOiBJU3RhdGljVGhpczxJLCBUPixcbiAgICBzdGF0ZTogbWFnZS5jb3JlLklTdGF0ZSxcbiAgICBpbmRleDogSSxcbiAgICBkYXRhPzogVG9waWNEYXRhPFQ+KTogUHJvbWlzZTxUPiB7XG5cbiAgICBsZXQgaW5zdGFuY2VcblxuICAgIGlmIChkYXRhKSB7XG4gICAgICBpZiAoIWlzT2JqZWN0KGRhdGEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgUmVjZWl2ZWQgZGF0YSBpcyBub3QgYW4gb2JqZWN0IChyZWNlaXZlZCAke0pTT04uc3RyaW5naWZ5KGRhdGEpfSlgKVxuICAgICAgfVxuXG4gICAgICBpbnN0YW5jZSA9IGNsYXNzVHJhbnNmb3JtZXIucGxhaW5Ub0NsYXNzPFQsIG9iamVjdD4odGhpcywgZGF0YSlcbiAgICB9IGVsc2Uge1xuICAgICAgaW5zdGFuY2UgPSBuZXcgdGhpcygpXG4gICAgfVxuXG4gICAgaW5zdGFuY2Uuc2V0VG9waWModGhpcy5nZXRDbGFzc05hbWUoKSlcbiAgICBpbnN0YW5jZS5zZXRTdGF0ZShzdGF0ZSlcbiAgICBhd2FpdCBpbnN0YW5jZS5zZXRJbmRleChpbmRleClcblxuICAgIHJldHVybiBpbnN0YW5jZVxuICB9XG5cbiAgLyoqXG4gICAqIFV0aWxpdHkgbWV0aG9kIHVzZWQgdG8gcHJvbWlzaWZ5IGFyY2hpdmlzdCBjYWxsc1xuICAgKlxuICAgKiBAc3RhdGljXG4gICAqIEBwYXJhbSB7Kn0gc3RhdGVcbiAgICogQHBhcmFtIHsqfSBtZXRob2RcbiAgICogQHBhcmFtIHthbnlbXX0gYXJnc1xuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBydW5cbiAgICogQHJldHVybnNcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIGV4ZWN1dGU8SSwgVCwgUj4oXG4gICAgdGhpczogSVN0YXRpY1RoaXM8SSwgVD4sXG4gICAgc3RhdGU6IGFueSxcbiAgICBtZXRob2Q6IGFueSxcbiAgICBhcmdzOiBhbnlbXSxcbiAgICBydW46IChkYXRhOiBhbnkpID0+IGFueSk6IFByb21pc2U8Uj4ge1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPFI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHN0YXRlLmFyY2hpdmlzdFttZXRob2RdKC4uLmFyZ3MsIChlcnJvcjogRXJyb3IsIGRhdGE6IFQpID0+IHtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgcmV0dXJuIHJlamVjdChlcnJvcilcbiAgICAgICAgfVxuXG4gICAgICAgIHJlc29sdmUocnVuKGRhdGEpKVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHRvcGljIGluc3RhbmNlIGZyb20gYmFja2VuZCB2YXVsdChzKVxuICAgKlxuICAgKiBNb3N0bHkgYSB3cmFwcGVyIGFyb3VuZCBzdGF0ZS5hcmNoaXZpc3QuZ2V0LiBOb3RlIHRoYXRcbiAgICogaW5zdGVhZCBvZiB1c2luZyB0aGUgYG9wdGlvbmFsYCBvcHRpb24gZGlyZWN0bHkgd2l0aCB0aGlzIGNhbGwsXG4gICAqIHlvdSBzaG91bGQgY29uc2lkZXIgdXNpbmcgYHRyeUdldGAgaW5zdGVhZCwgd2hpY2ggd2lsbCB0cmlnZ2VyIGFcbiAgICogY29tcGlsZSBlcnJvciBpZiB5b3UgZG8gbm90IGNoZWNrIGZvciBhbiB1bmRlZmluZWQgcmV0dXJuIHZhbHVlLlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqIEBwYXJhbSB7bWFnZS5jb3JlLklTdGF0ZX0gc3RhdGVcbiAgICogQHBhcmFtIHthcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4fSBpbmRleFxuICAgKiBAcGFyYW0ge2FyY2hpdmlzdC5JQXJjaGl2aXN0R2V0T3B0aW9uc30gW29wdGlvbnNdXG4gICAqIEByZXR1cm5zXG4gICAqXG4gICAqIEBtZW1iZXJvZiBWYWxpZGF0ZWRUb3BpY1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyBnZXQ8SSBleHRlbmRzIGFyY2hpdmlzdC5JQXJjaGl2aXN0SW5kZXgsIFQgZXh0ZW5kcyBWYWxpZGF0ZWRUb3BpYz4oXG4gICAgdGhpczogSVN0YXRpY1RoaXM8SSwgVD4sXG4gICAgc3RhdGU6IG1hZ2UuY29yZS5JU3RhdGUsXG4gICAgaW5kZXg6IEksXG4gICAgb3B0aW9ucz86IGFyY2hpdmlzdC5JQXJjaGl2aXN0R2V0T3B0aW9ucyk6IFByb21pc2U8VD4ge1xuXG4gICAgY29uc3QgdG9waWNOYW1lID0gdGhpcy5nZXRDbGFzc05hbWUoKVxuXG4gICAgcmV0dXJuIHRoaXMuZXhlY3V0ZTxJLCBULCBUPihzdGF0ZSwgJ2dldCcsIFtcbiAgICAgIHRvcGljTmFtZSxcbiAgICAgIGluZGV4LFxuICAgICAgb3B0aW9uc1xuICAgIF0sIGFzeW5jIChkYXRhOiBhbnkpID0+IHtcbiAgICAgIC8vIElmIG9wdGlvbmFsOiB0cnVlLCBhbmQgbm8gZGF0YSB3YXMgZm91bmRcbiAgICAgIGlmIChvcHRpb25zICYmIG9wdGlvbnMub3B0aW9uYWwgJiYgIWRhdGEpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcy5jcmVhdGUoc3RhdGUsIGluZGV4LCBkYXRhKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogVHJ5IHRvIGdldCBhIHRvcGljIGluc3RhbmNlIGZyb20gYmFja2VuZCB2YXVsdChzKVxuICAgKlxuICAgKiBTYW1lIGFzIGBnZXRgLCBidXQgaXMgYWxzbyBzdGF0ZXMgdGhhdCBgdW5kZWZpbmVkJyBtaWdodCBiZSByZXR1cm5lZCBpbnN0ZWFkLlxuICAgKiBZb3Ugc2hvdWxkIGNvbnNpZGVyIHVzaW5nIHRoaXMgbWV0aG9kIGluc3RlYWQgb2YgY2FsbGluZyBgZ2V0YCBkaXJlY3RseVxuICAgKiB3aXRoIHRoZSBgb3B0aW9uYWw6IHRydWVgIG9wdGlvbi5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAcGFyYW0ge21hZ2UuY29yZS5JU3RhdGV9IHN0YXRlXG4gICAqIEBwYXJhbSB7YXJjaGl2aXN0LklBcmNoaXZpc3RJbmRleH0gaW5kZXhcbiAgICogQHBhcmFtIHthcmNoaXZpc3QuSUFyY2hpdmlzdEdldE9wdGlvbnN9IFtvcHRpb25zXVxuICAgKiBAcmV0dXJuc1xuICAgKlxuICAgKiBAbWVtYmVyb2YgVmFsaWRhdGVkVG9waWNcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgYXN5bmMgdHJ5R2V0PEkgZXh0ZW5kcyBhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4LCBUIGV4dGVuZHMgVmFsaWRhdGVkVG9waWM+KFxuICAgIHRoaXM6IElTdGF0aWNUaGlzPEksIFQ+LFxuICAgIHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLFxuICAgIGluZGV4OiBJLFxuICAgIG9wdGlvbnM/OiBhcmNoaXZpc3QuSUFyY2hpdmlzdEdldE9wdGlvbnMpOiBQcm9taXNlPFQgfCB1bmRlZmluZWQ+IHtcblxuICAgIGlmICghb3B0aW9ucykge1xuICAgICAgb3B0aW9ucyA9IHt9XG4gICAgfVxuXG4gICAgb3B0aW9ucy5vcHRpb25hbCA9IHRydWVcblxuICAgIHJldHVybiB0aGlzLmdldChzdGF0ZSwgaW5kZXgsIG9wdGlvbnMpXG4gIH1cblxuICAvKipcbiAgICogR2V0IGluc3RhbmNlcyBmcm9tIGJhY2tlbmQgdmF1bHQocylcbiAgICpcbiAgICogTW9zdGx5IGEgd3JhcHBlciBhcm91bmQgc3RhdGUuYXJjaGl2aXN0Lm1nZXQuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQHBhcmFtIHttYWdlLmNvcmUuSVN0YXRlfSBzdGF0ZVxuICAgKiBAcGFyYW0ge2FyY2hpdmlzdC5JQXJjaGl2aXN0UXVlcnlbXX0gcXVlcmllc1xuICAgKiBAcGFyYW0ge2FyY2hpdmlzdC5JQXJjaGl2aXN0R2V0T3B0aW9uc30gW29wdGlvbnNdXG4gICAqIEByZXR1cm5zXG4gICAqXG4gICAqIEBtZW1iZXJvZiBWYWxpZGF0ZWRUb3BpY1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyBtZ2V0PEkgZXh0ZW5kcyBhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4LCBUIGV4dGVuZHMgVmFsaWRhdGVkVG9waWM+KFxuICAgIHRoaXM6IElTdGF0aWNUaGlzPEksIFQ+LFxuICAgIHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLFxuICAgIGluZGV4ZXM6IElbXSxcbiAgICBvcHRpb25zPzogYXJjaGl2aXN0LklBcmNoaXZpc3RHZXRPcHRpb25zKTogUHJvbWlzZTxUW10+IHtcblxuICAgIGNvbnN0IHRvcGljID0gdGhpcy5nZXRDbGFzc05hbWUoKVxuICAgIGNvbnN0IHF1ZXJpZXM6IGFyY2hpdmlzdC5JQXJjaGl2aXN0UXVlcnlbXSA9IGluZGV4ZXMubWFwKChpbmRleCkgPT4gKHsgdG9waWMsIGluZGV4IH0pKVxuXG4gICAgcmV0dXJuIHRoaXMuZXhlY3V0ZTxJLCBULCBUW10+KHN0YXRlLCAnbWdldCcsIFtcbiAgICAgIHF1ZXJpZXMsXG4gICAgICBvcHRpb25zXG4gICAgXSwgYXN5bmMgKGxpc3Q6IGFueSkgPT4ge1xuICAgICAgY29uc3QgaW5zdGFuY2VzOiBWYWxpZGF0ZWRUb3BpY1tdID0gW11cblxuICAgICAgZm9yIChjb25zdCBbaSwgZGF0YV0gb2YgbGlzdC5lbnRyaWVzKCkpIHtcbiAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGluZGV4ID0gcXVlcmllc1tpXS5pbmRleFxuICAgICAgICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IHRoaXMuY3JlYXRlKHN0YXRlLCBpbmRleCBhcyBJLCBkYXRhKVxuXG4gICAgICAgIGluc3RhbmNlcy5wdXNoKGluc3RhbmNlKVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gaW5zdGFuY2VzXG4gICAgfSlcbiAgfVxuXG4gIC8vXG4gIC8vIFRvZG86XG4gIC8vXG4gIC8vIHB1YmxpYyBzdGF0aWMgYXN5bmMgbWdldChzdGF0ZTogbWFnZS5jb3JlLklTdGF0ZSwgcXVlcmllczogYXJjaGl2aXN0LklOYW1lZEFyY2hpdmlzdFF1ZXJ5LCBvcHRpb25zPzogYXJjaGl2aXN0LklBcmNoaXZpc3RHZXRPcHRpb25zKSB7XG4gIC8vICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgLy8gICAgIHN0YXRlLmFyY2hpdmlzdC5tZ2V0KHF1ZXJpZXMsIG9wdGlvbnMsIGFzeW5jIChlcnJvciwgbGlzdCkgPT4ge1xuICAvLyAgICAgICBpZiAoZXJyb3IpIHtcbiAgLy8gICAgICAgICByZXR1cm4gcmVqZWN0KGVycm9yKVxuICAvLyAgICAgICB9XG5cbiAgLy8gICAgICAgY29uc3QgaW5zdGFuY2VzID0gT2JqZWN0LmtleXMobGlzdCkucmVkdWNlKChpbnN0YW5jZXMsIG5hbWUpID0+IHtcbiAgLy8gICAgICAgICBpZiAobGlzdFtuYW1lXSkge1xuICAvLyAgICAgICAgICAgaW5zdGFuY2VzW25hbWVdID0gdGhpcy5jcmVhdGUoc3RhdGUsIHF1ZXJpZXNbbmFtZV0sIGxpc3RbbmFtZV0pXG4gIC8vICAgICAgICAgfVxuXG4gIC8vICAgICAgICAgcmV0dXJuIGluc3RhbmNlc1xuICAvLyAgICAgICB9LCB7fSlcblxuICAvLyAgICAgICByZXNvbHZlKGluc3RhbmNlcylcbiAgLy8gICAgIH0pXG4gIC8vICAgfSlcbiAgLy8gfVxuXG4gIC8qKlxuICAgKiBMaXN0IGFsbCBrZXlzXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQHBhcmFtIHttYWdlLmNvcmUuSVN0YXRlfSBzdGF0ZVxuICAgKiBAcGFyYW0ge2FyY2hpdmlzdC5JQXJjaGl2aXN0SW5kZXh9IHBhcnRpYWxJbmRleFxuICAgKiBAcGFyYW0ge2FyY2hpdmlzdC5JQXJjaGl2aXN0R2V0T3B0aW9uc30gW29wdGlvbnNdXG4gICAqIEByZXR1cm5zXG4gICAqXG4gICAqIEBtZW1iZXJvZiBWYWxpZGF0ZWRUb3BpY1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyBsaXN0PEkgZXh0ZW5kcyBhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4LCBUIGV4dGVuZHMgVmFsaWRhdGVkVG9waWM+KFxuICAgIHRoaXM6IElTdGF0aWNUaGlzPEksIFQ+LFxuICAgIHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLFxuICAgIHBhcnRpYWxJbmRleDogUGFydGlhbEluZGV4PEk+LFxuICAgIG9wdGlvbnM/OiBhcmNoaXZpc3QuSUFyY2hpdmlzdExpc3RPcHRpb25zKTogUHJvbWlzZTxhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4W10+IHtcblxuICAgIGNvbnN0IHRvcGljTmFtZSA9IHRoaXMuZ2V0Q2xhc3NOYW1lKClcblxuICAgIHJldHVybiB0aGlzLmV4ZWN1dGU8SSwgVCwgSVtdPihzdGF0ZSwgJ2xpc3QnLCBbXG4gICAgICB0b3BpY05hbWUsXG4gICAgICBwYXJ0aWFsSW5kZXgsXG4gICAgICBvcHRpb25zLFxuICAgIF0sIChpbmRleGVzOiBhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4W10pID0+IGluZGV4ZXMpXG4gIH1cblxuICAvKipcbiAgICogUXVlcnkgZGF0YSBieSBwYXJ0aWFsIGluZGV4XG4gICAqXG4gICAqIEVzc2VudGlhbGx5IHdyYXBzIHN0YXRlLmFyY2hpdmlzdC5saXN0LCB0aGVuIGZldGNoZXMgdGhlIGRhdGFcbiAgICogZm9yIGVhY2gga2V5cyB1c2luZyBzdGF0ZS5hcmNoaXZpc3QubWdldC5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAcGFyYW0ge21hZ2UuY29yZS5JU3RhdGV9IHN0YXRlXG4gICAqIEBwYXJhbSB7YXJjaGl2aXN0LklBcmNoaXZpc3RJbmRleH0gcGFydGlhbEluZGV4XG4gICAqIEBwYXJhbSB7YXJjaGl2aXN0LklBcmNoaXZpc3RHZXRPcHRpb25zfSBbb3B0aW9uc11cbiAgICogQHJldHVybnNcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIHF1ZXJ5PEkgZXh0ZW5kcyBhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4LCBUIGV4dGVuZHMgVmFsaWRhdGVkVG9waWM+KFxuICAgIHRoaXM6IElTdGF0aWNUaGlzPEksIFQ+LFxuICAgIHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLFxuICAgIHBhcnRpYWxJbmRleDogUGFydGlhbEluZGV4PEk+LFxuICAgIG9wdGlvbnM/OiBhcmNoaXZpc3QuSUFyY2hpdmlzdEdldE9wdGlvbnMgfCBhcmNoaXZpc3QuSUFyY2hpdmlzdExpc3RPcHRpb25zKTogUHJvbWlzZTxUW10+IHtcblxuICAgIGNvbnN0IHRvcGljTmFtZSA9IHRoaXMuZ2V0Q2xhc3NOYW1lKClcblxuICAgIHJldHVybiB0aGlzLmV4ZWN1dGU8SSwgVCwgVFtdPihzdGF0ZSwgJ2xpc3QnLCBbXG4gICAgICB0b3BpY05hbWUsXG4gICAgICBwYXJ0aWFsSW5kZXgsXG4gICAgICBvcHRpb25zXG4gICAgXSwgYXN5bmMgKGluZGV4ZXM6IElbXSkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMubWdldDxUPihzdGF0ZSwgaW5kZXhlcywgb3B0aW9ucyBhcyBhcmNoaXZpc3QuSUFyY2hpdmlzdEdldE9wdGlvbnMpXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFZhbGlkYXRlZFRvcGljLlxuICAgKlxuICAgKiBAcGFyYW0ge21hZ2UuY29yZS5JU3RhdGV9IHN0YXRlXG4gICAqXG4gICAqIEBtZW1iZXJvZiBWYWxpZGF0ZWRUb3BpY1xuICAgKi9cbiAgY29uc3RydWN0b3Ioc3RhdGU/OiBtYWdlLmNvcmUuSVN0YXRlKSB7XG4gICAgdGhpcy5zZXRUb3BpYyh0aGlzLmNvbnN0cnVjdG9yLm5hbWUpXG5cbiAgICBpZiAoc3RhdGUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgdG9waWMgZm9yIHRoaXMgaW5zdGFuY2VcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgZ2V0VG9waWMoKSB7XG4gICAgcmV0dXJuIDxzdHJpbmc+ICg8YW55PiB0aGlzKS5fdG9waWNcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdGhlIHRvcGljIG5hbWUgZm9yIHRoaXMgaW5zdGFuY2VcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcGljTmFtZVxuICAgKlxuICAgKiBAbWVtYmVyb2YgVmFsaWRhdGVkVG9waWNcbiAgICovXG4gIHB1YmxpYyBzZXRUb3BpYyh0b3BpY05hbWU6IHN0cmluZykge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX3RvcGljJywge1xuICAgICAgdmFsdWU6IHRvcGljTmFtZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSB0b3BpYyBvZiB0aGF0IGluc3RhbmNlXG4gICAqXG4gICAqIFNob3VsZCBhbHdheXMgcmV0dXJuIHRoZSBjbGFzcyBuYW1lIG9mIHRoZSBpbnN0YW5jZS5cbiAgICpcbiAgICogQHJldHVybnNcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgZ2V0SW5kZXgoKSB7XG4gICAgcmV0dXJuIDxhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4PiAoPGFueT4gdGhpcykuX2luZGV4XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBpbmRleCBvZiB0aGlzIHRvcGljIGluc3RhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7YXJjaGl2aXN0LklBcmNoaXZpc3RJbmRleH0gaW5kZXhcbiAgICpcbiAgICogQG1lbWJlcm9mIFZhbGlkYXRlZFRvcGljXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgc2V0SW5kZXgoaW5kZXhEYXRhOiBhcmNoaXZpc3QuSUFyY2hpdmlzdEluZGV4KSB7XG4gICAgY29uc3QgQ2xhc3M6IGFueSA9IHRoaXMuY29uc3RydWN0b3JcbiAgICBjb25zdCBJbmRleCA9IENsYXNzLmluZGV4VHlwZVxuICAgIGNvbnN0IGluZGV4ID0gbmV3IEluZGV4KClcblxuICAgIGZvciAoY29uc3QgZmllbGQgb2YgQ2xhc3MuaW5kZXgpIHtcbiAgICAgIGluZGV4W2ZpZWxkXSA9IGluZGV4RGF0YVtmaWVsZF1cbiAgICB9XG5cbiAgICBjb25zdCBlcnJvcnMgPSBhd2FpdCBjbGFzc1ZhbGlkYXRvci52YWxpZGF0ZShpbmRleClcblxuICAgIGlmIChlcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcignSW5kZXggdmFsaWRhdGlvbiBmYWlsZWQnLCAnc2VydmVyJywge1xuICAgICAgICB0b3BpYzogdGhpcy5nZXRUb3BpYygpLFxuICAgICAgICBpbmRleDogdGhpcy5nZXRJbmRleCgpXG4gICAgICB9LCBlcnJvcnMpXG4gICAgfVxuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICdfaW5kZXgnLCB7XG4gICAgICB2YWx1ZTogaW5kZXgsXG4gICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlIHRoZSBzdGF0ZSBvYmplY3QgYXR0YWNoZWQgdG8gdGhlIGluc3RhbmNlXG4gICAqL1xuICBwdWJsaWMgZ2V0U3RhdGUoKSB7XG4gICAgcmV0dXJuIDxtYWdlLmNvcmUuSVN0YXRlPiAoPGFueT4gdGhpcykuX3N0YXRlXG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBzdGF0ZSB0aGlzIHRvcGljIGluc3RhbmNlIHdpbGwgYmUgdXNpbmcuXG4gICAqL1xuICBwdWJsaWMgc2V0U3RhdGUoc3RhdGU6IG1hZ2UuY29yZS5JU3RhdGUpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ19zdGF0ZScsIHtcbiAgICAgIHZhbHVlOiBzdGF0ZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmUgdGhlIGFjdHVhbCBkYXRhIGZvciB0aGlzIGluc3RhbmNlXG4gICAqXG4gICAqIFRoaXMgc2hvdWxkIGVzc2VudGlhbGx5IGJlIHRoZSBzYW1lIGFzIHNpbXBseSBhY2Nlc3NpbmcgZGF0YSBvbiB0aGVcbiAgICogaW5zdGFuY2UgaXRzZWxmLlxuICAgKi9cbiAgcHVibGljIGdldERhdGEoKSB7XG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgYW4gYWRkIG9wZXJhdGlvbiBvbiB0aGUgaW5zdGFuY2UncyBzdGF0ZVxuICAgKlxuICAgKiBFc3NlbnRpYWxseSBhIHdyYXBwZXIgZm9yIHN0YXRlLmFyY2hpdmlzdC5hZGRcbiAgICovXG4gIHB1YmxpYyBhc3luYyBhZGQobWVkaWFUeXBlPzogYXJjaGl2aXN0LkFyY2hpdmlzdE1lZGlhVHlwZSwgZW5jb2Rpbmc/OiBhcmNoaXZpc3QuQXJjaGl2aXN0RW5jb2RpbmcsIGV4cGlyYXRpb25UaW1lPzogbnVtYmVyKSB7XG4gICAgYXdhaXQgdGhpcy52YWxpZGF0ZSgnVmFsaWRhdGlvbiBmYWlsZWQgb24gYWRkJylcbiAgICByZXR1cm4gdGhpcy5nZXRTdGF0ZSgpLmFyY2hpdmlzdC5hZGQodGhpcy5nZXRUb3BpYygpLCB0aGlzLmdldEluZGV4KCksIHRoaXMuZ2V0RGF0YSgpLCBtZWRpYVR5cGUsIGVuY29kaW5nLCBleHBpcmF0aW9uVGltZSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgYSBzZXQgb3BlcmF0aW9uIG9uIHRoZSBpbnN0YW5jZSdzIHN0YXRlXG4gICAqXG4gICAqIEVzc2VudGlhbGx5IGEgd3JhcHBlciBmb3Igc3RhdGUuYXJjaGl2aXN0LnNldC5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBzZXQobWVkaWFUeXBlPzogYXJjaGl2aXN0LkFyY2hpdmlzdE1lZGlhVHlwZSwgZW5jb2Rpbmc/OiBhcmNoaXZpc3QuQXJjaGl2aXN0RW5jb2RpbmcsIGV4cGlyYXRpb25UaW1lPzogbnVtYmVyKSB7XG4gICAgYXdhaXQgdGhpcy52YWxpZGF0ZSgnVmFsaWRhdGlvbiBmYWlsZWQgb24gc2V0JylcbiAgICByZXR1cm4gdGhpcy5nZXRTdGF0ZSgpLmFyY2hpdmlzdC5zZXQodGhpcy5nZXRUb3BpYygpLCB0aGlzLmdldEluZGV4KCksIHRoaXMuZ2V0RGF0YSgpLCBtZWRpYVR5cGUsIGVuY29kaW5nLCBleHBpcmF0aW9uVGltZSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgYSB0b3VjaCBvcGVyYXRpb24gb24gdGhlIGluc3RhbmNlJ3Mgc3RhdGVcbiAgICpcbiAgICogRXNzZW50aWFsbHkgYSB3cmFwcGVyIGZvciBzdGF0ZS5hcmNoaXZpc3QudG91Y2guXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgdG91Y2goZXhwaXJhdGlvblRpbWU/OiBudW1iZXIpIHtcbiAgICBhd2FpdCB0aGlzLnZhbGlkYXRlKCdWYWxpZGF0aW9uIGZhaWxlZCBvbiB0b3VjaCcpXG4gICAgcmV0dXJuIHRoaXMuZ2V0U3RhdGUoKS5hcmNoaXZpc3QudG91Y2godGhpcy5nZXRUb3BpYygpLCB0aGlzLmdldEluZGV4KCksIGV4cGlyYXRpb25UaW1lKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBhIGRlbGV0ZSBvcGVyYXRpb24gb24gdGhlIGluc3RhbmNlJ3Mgc3RhdGVcbiAgICovXG4gIHB1YmxpYyBkZWwoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U3RhdGUoKS5hcmNoaXZpc3QuZGVsKHRoaXMuZ2V0VG9waWMoKSwgdGhpcy5nZXRJbmRleCgpKVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoZSBjdXJyZW50IGluc3RhbmNlXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgdmFsaWRhdGUoZXJyb3JNZXNzYWdlPzogc3RyaW5nLCBjb2RlPzogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZXJyb3JzID0gYXdhaXQgY2xhc3NWYWxpZGF0b3IudmFsaWRhdGUodGhpcylcbiAgICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMucmFpc2VWYWxpZGF0aW9uRXJyb3IoZXJyb3JzLCBlcnJvck1lc3NhZ2UsIGNvZGUpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRocm93IGEgVmFsaWRhdGVFcnJvciBpbmNsdWRpbmcgcmVsZXZhbnQgZGV0YWlsc1xuICAgKi9cbiAgcHVibGljIHJhaXNlVmFsaWRhdGlvbkVycm9yKGVycm9yczogYW55W10sIGVycm9yTWVzc2FnZT86IHN0cmluZywgY29kZT86IHN0cmluZykge1xuICAgIGNvbnN0IHN0YXRlID0gPGFueT4gdGhpcy5nZXRTdGF0ZSgpXG5cbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKGVycm9yTWVzc2FnZSB8fCAnVmFsaWRhdGlvbiBmYWlsZWQnLCBjb2RlIHx8ICdzZXJ2ZXInLCB7XG4gICAgICBhY3RvcklkOiBzdGF0ZS5hY3RvcklkLFxuICAgICAgdXNlckNvbW1hbmQ6IHN0YXRlLmRlc2NyaXB0aW9uLFxuICAgICAgdG9waWM6IHRoaXMuZ2V0VG9waWMoKSxcbiAgICAgIGluZGV4OiB0aGlzLmdldEluZGV4KClcbiAgICB9LCBlcnJvcnMpXG4gIH1cbn1cbiJdfQ==