@decaf-ts/db-decorators
Version:
Agnostic database decorators and repository
229 lines • 31.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashOnCreateUpdate = hashOnCreateUpdate;
exports.hash = hash;
exports.composedFromCreateUpdate = composedFromCreateUpdate;
exports.composedFromKeys = composedFromKeys;
exports.composed = composed;
exports.versionCreateUpdate = versionCreateUpdate;
exports.version = version;
exports.transient = transient;
const constants_1 = require("./constants.cjs");
const reflection_1 = require("@decaf-ts/reflection");
const decorator_validation_1 = require("@decaf-ts/decorator-validation");
const decorators_1 = require("./../operations/decorators.cjs");
const errors_1 = require("./../repository/errors.cjs");
const Repository_1 = require("./../repository/Repository.cjs");
const operations_1 = require("./../operations/index.cjs");
/**
* @description Hashes a property value during create or update operations
* @summary Callback function used by the hash decorator to apply hashing to a property value
* @template M - Type extending Model
* @template R - Type extending IRepository
* @template V - Type for metadata
* @template F - Type extending RepositoryFlags
* @template C - Type extending Context
* @param {C} context - The operation context
* @param {V} data - Metadata for the operation
* @param key - The property key to hash
* @param {M} model - The model being processed
* @param {M} [oldModel] - The previous model state (for updates)
* @return {void}
* @function hashOnCreateUpdate
* @memberOf module:db-decorators
*/
function hashOnCreateUpdate(context, data, key, model, oldModel) {
if (typeof model[key] === "undefined")
return;
const hash = decorator_validation_1.Hashing.hash(model[key]);
if (oldModel && model[key] === hash)
return;
model[key] = hash;
}
/**
* @description Creates a decorator that hashes a property value
* @summary Decorator that automatically hashes a property value during create and update operations
* @return {PropertyDecorator} A decorator that can be applied to class properties
* @function hash
* @category Property Decorators
*/
function hash() {
return (0, reflection_1.apply)((0, decorators_1.onCreateUpdate)(hashOnCreateUpdate), (0, decorator_validation_1.propMetadata)(Repository_1.Repository.key(constants_1.DBKeys.HASH), {}));
}
/**
* @description Composes a property value from other properties during create or update operations
* @summary Callback function used by composed decorators to generate a property value from other properties
* @template M - Type extending Model
* @template R - Type extending IRepository
* @template V - Type extending ComposedFromMetadata
* @template F - Type extending RepositoryFlags
* @template C - Type extending Context
* @param {C} context - The operation context
* @param {V} data - Metadata for the composition
* @param key - The property key to set the composed value on
* @param {M} model - The model being processed
* @return {void}
* @function composedFromCreateUpdate
* @memberOf module:db-decorators
*/
function composedFromCreateUpdate(context, data, key, model) {
try {
const { args, type, prefix, suffix, separator } = data;
const composed = args.map((arg) => {
if (!(arg in model))
throw new errors_1.InternalError(`Property ${arg} not found to compose from`);
if (type === "keys")
return arg;
if (typeof model[arg] === "undefined")
throw new errors_1.InternalError(`Property ${args} does not contain a value to compose from`);
return model[arg].toString();
});
if (prefix)
composed.unshift(prefix);
if (suffix)
composed.push(suffix);
model[key] = composed.join(separator);
}
catch (e) {
throw new errors_1.InternalError(`Failed to compose value: ${e}`);
}
}
/**
* @description Creates a decorator that composes a property value from other properties
* @summary Base function for creating property composition decorators
* @param {string[]} args - Property names to compose from
* @param {boolean} [hashResult=false] - Whether to hash the composed result
* @param {string} [separator=DefaultSeparator] - Character used to join the composed values
* @param {"keys"|"values"} [type="values"] - Whether to use property keys or values
* @param {string} [prefix=""] - Optional prefix to add to the composed value
* @param {string} [suffix=""] - Optional suffix to add to the composed value
* @return {PropertyDecorator} A decorator that can be applied to class properties
* @function composedFrom
* @category PropertyDecorators
*/
function composedFrom(args, hashResult = false, separator = constants_1.DefaultSeparator, type = "values", prefix = "", suffix = "") {
const data = {
args: args,
hashResult: hashResult,
separator: separator,
type: type,
prefix: prefix,
suffix: suffix,
};
const decorators = [
(0, decorators_1.onCreateUpdate)(composedFromCreateUpdate, data),
(0, decorator_validation_1.propMetadata)(Repository_1.Repository.key(constants_1.DBKeys.COMPOSED), data),
];
if (hashResult)
decorators.push(hash());
return (0, reflection_1.apply)(...decorators);
}
/**
* @description Creates a decorator that composes a property value from property keys
* @summary Decorator that generates a property value by joining the names of other properties
* @param {string[]} args - Property names to compose from
* @param {string} [separator=DefaultSeparator] - Character used to join the property names
* @param {boolean} [hash=false] - Whether to hash the composed result
* @param {string} [prefix=""] - Optional prefix to add to the composed value
* @param {string} [suffix=""] - Optional suffix to add to the composed value
* @return {PropertyDecorator} A decorator that can be applied to class properties
* @function composedFromKeys
* @category PropertyDecorators
*/
function composedFromKeys(args, separator = constants_1.DefaultSeparator, hash = false, prefix = "", suffix = "") {
return composedFrom(args, hash, separator, "keys", prefix, suffix);
}
/**
* @description Creates a decorator that composes a property value from property values
* @summary Decorator that generates a property value by joining the values of other properties
* @param {string[]} args - Property names whose values will be composed
* @param {string} [separator=DefaultSeparator] - Character used to join the property values
* @param {boolean} [hash=false] - Whether to hash the composed result
* @param {string} [prefix=""] - Optional prefix to add to the composed value
* @param {string} [suffix=""] - Optional suffix to add to the composed value
* @return {PropertyDecorator} A decorator that can be applied to class properties
* @function composed
* @category PropertyDecorators
*/
function composed(args, separator = constants_1.DefaultSeparator, hash = false, prefix = "", suffix = "") {
return composedFrom(args, hash, separator, "values", prefix, suffix);
}
/**
* @description Creates a function that updates a version property during operations
* @summary Factory function that generates a callback for incrementing version numbers
* @param {CrudOperations} operation - The type of operation (CREATE or UPDATE)
* @return {Function} A callback function that updates the version property
* @template M - Type extending Model
* @template R - Type extending IRepository
* @template V - Type for metadata
* @template F - Type extending RepositoryFlags
* @template C - Type extending Context
* @function versionCreateUpdate
* @memberOf module:db-decorators
* @mermaid
* sequenceDiagram
* participant Caller
* participant versionCreateUpdate
*
* Caller->>versionCreateUpdate: operation
* versionCreateUpdate-->>Caller: callback function
* Note over Caller,versionCreateUpdate: When callback is executed:
* Caller->>versionCreateUpdate: context, data, key, model
* alt operation is CREATE
* versionCreateUpdate->>versionCreateUpdate: set version to 1
* else operation is UPDATE
* versionCreateUpdate->>versionCreateUpdate: increment version
* else invalid operation
* versionCreateUpdate->>versionCreateUpdate: throw error
* end
* versionCreateUpdate-->>Caller: void
*/
function versionCreateUpdate(operation) {
return function versionCreateUpdate(context, data, key, model) {
try {
switch (operation) {
case operations_1.OperationKeys.CREATE:
model[key] = 1;
break;
case operations_1.OperationKeys.UPDATE:
model[key]++;
break;
default:
throw new errors_1.InternalError(`Invalid operation: ${operation}`);
}
}
catch (e) {
throw new errors_1.InternalError(`Failed to update version: ${e}`);
}
};
}
/**
* @description Creates a decorator for versioning a property in a model
* @summary This decorator applies multiple sub-decorators to handle version management during create and update operations
* @return {PropertyDecorator} A composite decorator that sets the type to Number, manages version updates, and adds versioning metadata
* @function version
* @category PropertyDecorators
*/
function version() {
const key = Repository_1.Repository.key(constants_1.DBKeys.VERSION);
return decorator_validation_1.Decoration.for(key)
.define((0, decorator_validation_1.type)(Number.name), (0, decorators_1.onCreate)(versionCreateUpdate(operations_1.OperationKeys.CREATE)), (0, decorators_1.onUpdate)(versionCreateUpdate(operations_1.OperationKeys.UPDATE)), (0, decorator_validation_1.propMetadata)(key, true))
.apply();
}
/**
* @description Creates a decorator that marks a property as transient
* @summary Decorator that indicates a property should not be persisted to the database
* @return {PropertyDecorator} A decorator that can be applied to class properties
* @function transient
* @category PropertyDecorators
*/
function transient() {
const key = Repository_1.Repository.key(constants_1.DBKeys.TRANSIENT);
return decorator_validation_1.Decoration.for(key)
.define(function transient(model, attribute) {
(0, decorator_validation_1.propMetadata)(Repository_1.Repository.key(constants_1.DBKeys.TRANSIENT), true)(model, attribute);
(0, decorator_validation_1.propMetadata)(Repository_1.Repository.key(constants_1.DBKeys.TRANSIENT), true)(model.constructor);
})
.apply();
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVjb3JhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tb2RlbC9kZWNvcmF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBa0NBLGdEQVdDO0FBU0Qsb0JBS0M7QUF1Q0QsNERBMkJDO0FBb0RELDRDQVFDO0FBY0QsNEJBUUM7QUFnQ0Qsa0RBdUJDO0FBU0QsMEJBVUM7QUFTRCw4QkFRQztBQTFTRCwrQ0FBdUQ7QUFDdkQscURBQTZDO0FBQzdDLHlFQU13QztBQUN4QywrREFBOEU7QUFFOUUsdURBQXFEO0FBQ3JELCtEQUFzRDtBQUV0RCwwREFBOEQ7QUFHOUQ7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxTQUFnQixrQkFBa0IsQ0FNdkIsT0FBVSxFQUFFLElBQU8sRUFBRSxHQUFZLEVBQUUsS0FBUSxFQUFFLFFBQVk7SUFDbEUsSUFBSSxPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxXQUFXO1FBQUUsT0FBTztJQUM5QyxNQUFNLElBQUksR0FBRyw4QkFBTyxDQUFDLElBQUksQ0FBRSxLQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMvQyxJQUFJLFFBQVEsSUFBSyxLQUFhLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSTtRQUFFLE9BQU87SUFDckQsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztBQUNwQixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsSUFBSTtJQUNsQixPQUFPLElBQUEsa0JBQUssRUFDVixJQUFBLDJCQUFjLEVBQUMsa0JBQWtCLENBQUMsRUFDbEMsSUFBQSxtQ0FBWSxFQUFDLHVCQUFVLENBQUMsR0FBRyxDQUFDLGtCQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQzlDLENBQUM7QUFDSixDQUFDO0FBdUJEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILFNBQWdCLHdCQUF3QixDQU03QixPQUFVLEVBQUUsSUFBTyxFQUFFLEdB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QUVEOzs7Ozs7R0FNRztBQUNILFNBQWdCLFNBQVM7SUFDdkIsTUFBTSxHQUFHLEdBQUcsdUJBQVUsQ0FBQyxHQUFHLENBQUMsa0JBQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM3QyxPQUFPLGlDQUFVLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztTQUN2QixNQUFNLENBQUMsU0FBUyxTQUFTLENBQUMsS0FBVSxFQUFFLFNBQWM7UUFDbkQsSUFBQSxtQ0FBWSxFQUFDLHVCQUFVLENBQUMsR0FBRyxDQUFDLGtCQUFNLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ3ZFLElBQUEsbUNBQVksRUFBQyx1QkFBVSxDQUFDLEdBQUcsQ0FBQyxrQkFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMxRSxDQUFDLENBQUM7U0FDRCxLQUFLLEVBQUUsQ0FBQztBQUNiLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEQktleXMsIERlZmF1bHRTZXBhcmF0b3IgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGFwcGx5IH0gZnJvbSBcIkBkZWNhZi10cy9yZWZsZWN0aW9uXCI7XG5pbXBvcnQge1xuICBEZWNvcmF0aW9uLFxuICBIYXNoaW5nLFxuICBNb2RlbCxcbiAgcHJvcE1ldGFkYXRhLFxuICB0eXBlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBvbkNyZWF0ZSwgb25DcmVhdGVVcGRhdGUsIG9uVXBkYXRlIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlcy9JUmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L2Vycm9yc1wiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L1JlcG9zaXRvcnlcIjtcbmltcG9ydCB7IENvbnRleHQgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeS9Db250ZXh0XCI7XG5pbXBvcnQgeyBDcnVkT3BlcmF0aW9ucywgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCIuLi9vcGVyYXRpb25zXCI7XG5pbXBvcnQgeyBSZXBvc2l0b3J5RmxhZ3MgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeS90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBIYXNoZXMgYSBwcm9wZXJ0eSB2YWx1ZSBkdXJpbmcgY3JlYXRlIG9yIHVwZGF0ZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBDYWxsYmFjayBmdW5jdGlvbiB1c2VkIGJ5IHRoZSBoYXNoIGRlY29yYXRvciB0byBhcHBseSBoYXNoaW5nIHRvIGEgcHJvcGVydHkgdmFsdWVcbiAqIEB0ZW1wbGF0ZSBNIC0gVHlwZSBleHRlbmRpbmcgTW9kZWxcbiAqIEB0ZW1wbGF0ZSBSIC0gVHlwZSBleHRlbmRpbmcgSVJlcG9zaXRvcnlcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGFcbiAqIEB0ZW1wbGF0ZSBGIC0gVHlwZSBleHRlbmRpbmcgUmVwb3NpdG9yeUZsYWdzXG4gKiBAdGVtcGxhdGUgQyAtIFR5cGUgZXh0ZW5kaW5nIENvbnRleHRcbiAqIEBwYXJhbSB7Q30gY29udGV4dCAtIFRoZSBvcGVyYXRpb24gY29udGV4dFxuICogQHBhcmFtIHtWfSBkYXRhIC0gTWV0YWRhdGEgZm9yIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSBrZXkgLSBUaGUgcHJvcGVydHkga2V5IHRvIGhhc2hcbiAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgYmVpbmcgcHJvY2Vzc2VkXG4gKiBAcGFyYW0ge019IFtvbGRNb2RlbF0gLSBUaGUgcHJldmlvdXMgbW9kZWwgc3RhdGUgKGZvciB1cGRhdGVzKVxuICogQHJldHVybiB7dm9pZH1cbiAqIEBmdW5jdGlvbiBoYXNoT25DcmVhdGVVcGRhdGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzaE9uQ3JlYXRlVXBkYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBJUmVwb3NpdG9yeTxNLCBGLCBDPixcbiAgViBleHRlbmRzIG9iamVjdCxcbiAgRiBleHRlbmRzIFJlcG9zaXRvcnlGbGFncyA9IFJlcG9zaXRvcnlGbGFncyxcbiAgQyBleHRlbmRzIENvbnRleHQ8Rj4gPSBDb250ZXh0PEY+LFxuPih0aGlzOiBSLCBjb250ZXh0OiBDLCBkYXRhOiBWLCBrZXk6IGtleW9mIE0sIG1vZGVsOiBNLCBvbGRNb2RlbD86IE0pOiB2b2lkIHtcbiAgaWYgKHR5cGVvZiBtb2RlbFtrZXldID09PSBcInVuZGVmaW5lZFwiKSByZXR1cm47XG4gIGNvbnN0IGhhc2ggPSBIYXNoaW5nLmhhc2goKG1vZGVsIGFzIGFueSlba2V5XSk7XG4gIGlmIChvbGRNb2RlbCAmJiAobW9kZWwgYXMgYW55KVtrZXldID09PSBoYXNoKSByZXR1cm47XG4gIG1vZGVsW2tleV0gPSBoYXNoO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgZGVjb3JhdG9yIHRoYXQgaGFzaGVzIGEgcHJvcGVydHkgdmFsdWVcbiAqIEBzdW1tYXJ5IERlY29yYXRvciB0aGF0IGF1dG9tYXRpY2FsbHkgaGFzaGVzIGEgcHJvcGVydHkgdmFsdWUgZHVyaW5nIGNyZWF0ZSBhbmQgdXBkYXRlIG9wZXJhdGlvbnNcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiBoYXNoXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzaCgpIHtcbiAgcmV0dXJuIGFwcGx5KFxuICAgIG9uQ3JlYXRlVXBkYXRlKGhhc2hPbkNyZWF0ZVVwZGF0ZSksXG4gICAgcHJvcE1ldGFkYXRhKFJlcG9zaXRvcnkua2V5KERCS2V5cy5IQVNIKSwge30pXG4gICk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1ldGFkYXRhIGZvciBjb21wb3NlZCBwcm9wZXJ0eSBkZWNvcmF0b3JzXG4gKiBAc3VtbWFyeSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHByb3BlcnR5IGNvbXBvc2l0aW9uIGZyb20gb3RoZXIgcHJvcGVydGllc1xuICogQHR5cGVkZWYge09iamVjdH0gQ29tcG9zZWRGcm9tTWV0YWRhdGFcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IGFyZ3MgLSBQcm9wZXJ0eSBuYW1lcyB0byBjb21wb3NlIGZyb21cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzZXBhcmF0b3IgLSBDaGFyYWN0ZXIgdXNlZCB0byBqb2luIHRoZSBjb21wb3NlZCB2YWx1ZXNcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gaGFzaFJlc3VsdCAtIFdoZXRoZXIgdG8gaGFzaCB0aGUgY29tcG9zZWQgcmVzdWx0XG4gKiBAcHJvcGVydHkge1wia2V5c1wifFwidmFsdWVzXCJ9IHR5cGUgLSBXaGV0aGVyIHRvIHVzZSBwcm9wZXJ0eSBrZXlzIG9yIHZhbHVlc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IFtwcmVmaXhdIC0gT3B0aW9uYWwgcHJlZml4IHRvIGFkZCB0byB0aGUgY29tcG9zZWQgdmFsdWVcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBbc3VmZml4XSAtIE9wdGlvbmFsIHN1ZmZpeCB0byBhZGQgdG8gdGhlIGNvbXBvc2VkIHZhbHVlXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuZXhwb3J0IHR5cGUgQ29tcG9zZWRGcm9tTWV0YWRhdGEgPSB7XG4gIGFyZ3M6IHN0cmluZ1tdO1xuICBzZXBhcmF0b3I6IHN0cmluZztcbiAgaGFzaFJlc3VsdDogYm9vbGVhbjtcbiAgdHlwZTogXCJrZXlzXCIgfCBcInZhbHVlc1wiO1xuICBwcmVmaXg/OiBzdHJpbmc7XG4gIHN1ZmZpeD86IHN0cmluZztcbn07XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbXBvc2VzIGEgcHJvcGVydHkgdmFsdWUgZnJvbSBvdGhlciBwcm9wZXJ0aWVzIGR1cmluZyBjcmVhdGUgb3IgdXBkYXRlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IENhbGxiYWNrIGZ1bmN0aW9uIHVzZWQgYnkgY29tcG9zZWQgZGVjb3JhdG9ycyB0byBnZW5lcmF0ZSBhIHByb3BlcnR5IHZhbHVlIGZyb20gb3RoZXIgcHJvcGVydGllc1xuICogQHRlbXBsYXRlIE0gLSBUeXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHRlbXBsYXRlIFIgLSBUeXBlIGV4dGVuZGluZyBJUmVwb3NpdG9yeVxuICogQHRlbXBsYXRlIFYgLSBUeXBlIGV4dGVuZGluZyBDb21wb3NlZEZyb21NZXRhZGF0YVxuICogQHRlbXBsYXRlIEYgLSBUeXBlIGV4dGVuZGluZyBSZXBvc2l0b3J5RmxhZ3NcbiAqIEB0ZW1wbGF0ZSBDIC0gVHlwZSBleHRlbmRpbmcgQ29udGV4dFxuICogQHBhcmFtIHtDfSBjb250ZXh0IC0gVGhlIG9wZXJhdGlvbiBjb250ZXh0XG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBNZXRhZGF0YSBmb3IgdGhlIGNvbXBvc2l0aW9uXG4gKiBAcGFyYW0ga2V5IC0gVGhlIHByb3BlcnR5IGtleSB0byBzZXQgdGhlIGNvbXBvc2VkIHZhbHVlIG9uXG4gKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGJlaW5nIHByb2Nlc3NlZFxuICogQHJldHVybiB7dm9pZH1cbiAqIEBmdW5jdGlvbiBjb21wb3NlZEZyb21DcmVhdGVVcGRhdGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcG9zZWRGcm9tQ3JlYXRlVXBkYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBJUmVwb3NpdG9yeTxNLCBGLCBDPixcbiAgViBleHRlbmRzIENvbXBvc2VkRnJvbU1ldGFkYXRhLFxuICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzID0gUmVwb3NpdG9yeUZsYWdzLFxuICBDIGV4dGVuZHMgQ29udGV4dDxGPiA9IENvbnRleHQ8Rj4sXG4+KHRoaXM6IFIsIGNvbnRleHQ6IEMsIGRhdGE6IFYsIGtleToga2V5b2YgTSwgbW9kZWw6IE0pIHtcbiAgdHJ5IHtcbiAgICBjb25zdCB7IGFyZ3MsIHR5cGUsIHByZWZpeCwgc3VmZml4LCBzZXBhcmF0b3IgfSA9IGRhdGE7XG4gICAgY29uc3QgY29tcG9zZWQgPSBhcmdzLm1hcCgoYXJnOiBzdHJpbmcpID0+IHtcbiAgICAgIGlmICghKGFyZyBpbiBtb2RlbCkpXG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBQcm9wZXJ0eSAke2FyZ30gbm90IGZvdW5kIHRvIGNvbXBvc2UgZnJvbWApO1xuICAgICAgaWYgKHR5cGUgPT09IFwia2V5c1wiKSByZXR1cm4gYXJnO1xuICAgICAgaWYgKHR5cGVvZiAobW9kZWwgYXMgYW55KVthcmddID09PSBcInVuZGVmaW5lZFwiKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICBgUHJvcGVydHkgJHthcmdzfSBkb2VzIG5vdCBjb250YWluIGEgdmFsdWUgdG8gY29tcG9zZSBmcm9tYFxuICAgICAgICApO1xuICAgICAgcmV0dXJuICgobW9kZWwgYXMgYW55KVthcmddIGFzIGFueSkudG9TdHJpbmcoKTtcbiAgICB9KTtcblxuICAgIGlmIChwcmVmaXgpIGNvbXBvc2VkLnVuc2hpZnQocHJlZml4KTtcbiAgICBpZiAoc3VmZml4KSBjb21wb3NlZC5wdXNoKHN1ZmZpeCk7XG5cbiAgICAobW9kZWwgYXMgYW55KVtrZXldID0gY29tcG9zZWQuam9pbihzZXBhcmF0b3IpO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgRmFpbGVkIHRvIGNvbXBvc2UgdmFsdWU6ICR7ZX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgZGVjb3JhdG9yIHRoYXQgY29tcG9zZXMgYSBwcm9wZXJ0eSB2YWx1ZSBmcm9tIG90aGVyIHByb3BlcnRpZXNcbiAqIEBzdW1tYXJ5IEJhc2UgZnVuY3Rpb24gZm9yIGNyZWF0aW5nIHByb3BlcnR5IGNvbXBvc2l0aW9uIGRlY29yYXRvcnNcbiAqIEBwYXJhbSB7c3RyaW5nW119IGFyZ3MgLSBQcm9wZXJ0eSBuYW1lcyB0byBjb21wb3NlIGZyb21cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhc2hSZXN1bHQ9ZmFsc2VdIC0gV2hldGhlciB0byBoYXNoIHRoZSBjb21wb3NlZCByZXN1bHRcbiAqIEBwYXJhbSB7c3RyaW5nfSBbc2VwYXJhdG9yPURlZmF1bHRTZXBhcmF0b3JdIC0gQ2hhcmFjdGVyIHVzZWQgdG8gam9pbiB0aGUgY29tcG9zZWQgdmFsdWVzXG4gKiBAcGFyYW0ge1wia2V5c1wifFwidmFsdWVzXCJ9IFt0eXBlPVwidmFsdWVzXCJdIC0gV2hldGhlciB0byB1c2UgcHJvcGVydHkga2V5cyBvciB2YWx1ZXNcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJlZml4PVwiXCJdIC0gT3B0aW9uYWwgcHJlZml4IHRvIGFkZCB0byB0aGUgY29tcG9zZWQgdmFsdWVcbiAqIEBwYXJhbSB7c3RyaW5nfSBbc3VmZml4PVwiXCJdIC0gT3B0aW9uYWwgc3VmZml4IHRvIGFkZCB0byB0aGUgY29tcG9zZWQgdmFsdWVcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiBjb21wb3NlZEZyb21cbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eURlY29yYXRvcnNcbiAqL1xuZnVuY3Rpb24gY29tcG9zZWRGcm9tKFxuICBhcmdzOiBzdHJpbmdbXSxcbiAgaGFzaFJlc3VsdDogYm9vbGVhbiA9IGZhbHNlLFxuICBzZXBhcmF0b3I6IHN0cmluZyA9IERlZmF1bHRTZXBhcmF0b3IsXG4gIHR5cGU6IFwia2V5c1wiIHwgXCJ2YWx1ZXNcIiA9IFwidmFsdWVzXCIsXG4gIHByZWZpeCA9IFwiXCIsXG4gIHN1ZmZpeCA9IFwiXCJcbikge1xuICBjb25zdCBkYXRhOiBDb21wb3NlZEZyb21NZXRhZGF0YSA9IHtcbiAgICBhcmdzOiBhcmdzLFxuICAgIGhhc2hSZXN1bHQ6IGhhc2hSZXN1bHQsXG4gICAgc2VwYXJhdG9yOiBzZXBhcmF0b3IsXG4gICAgdHlwZTogdHlwZSxcbiAgICBwcmVmaXg6IHByZWZpeCxcbiAgICBzdWZmaXg6IHN1ZmZpeCxcbiAgfTtcblxuICBjb25zdCBkZWNvcmF0b3JzID0gW1xuICAgIG9uQ3JlYXRlVXBkYXRlKGNvbXBvc2VkRnJvbUNyZWF0ZVVwZGF0ZSwgZGF0YSksXG4gICAgcHJvcE1ldGFkYXRhKFJlcG9zaXRvcnkua2V5KERCS2V5cy5DT01QT1NFRCksIGRhdGEpLFxuICBdO1xuICBpZiAoaGFzaFJlc3VsdCkgZGVjb3JhdG9ycy5wdXNoKGhhc2goKSk7XG4gIHJldHVybiBhcHBseSguLi5kZWNvcmF0b3JzKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGRlY29yYXRvciB0aGF0IGNvbXBvc2VzIGEgcHJvcGVydHkgdmFsdWUgZnJvbSBwcm9wZXJ0eSBrZXlzXG4gKiBAc3VtbWFyeSBEZWNvcmF0b3IgdGhhdCBnZW5lcmF0ZXMgYSBwcm9wZXJ0eSB2YWx1ZSBieSBqb2luaW5nIHRoZSBuYW1lcyBvZiBvdGhlciBwcm9wZXJ0aWVzXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBhcmdzIC0gUHJvcGVydHkgbmFtZXMgdG8gY29tcG9zZSBmcm9tXG4gKiBAcGFyYW0ge3N0cmluZ30gW3NlcGFyYXRvcj1EZWZhdWx0U2VwYXJhdG9yXSAtIENoYXJhY3RlciB1c2VkIHRvIGpvaW4gdGhlIHByb3BlcnR5IG5hbWVzXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtoYXNoPWZhbHNlXSAtIFdoZXRoZXIgdG8gaGFzaCB0aGUgY29tcG9zZWQgcmVzdWx0XG4gKiBAcGFyYW0ge3N0cmluZ30gW3ByZWZpeD1cIlwiXSAtIE9wdGlvbmFsIHByZWZpeCB0byBhZGQgdG8gdGhlIGNvbXBvc2VkIHZhbHVlXG4gKiBAcGFyYW0ge3N0cmluZ30gW3N1ZmZpeD1cIlwiXSAtIE9wdGlvbmFsIHN1ZmZpeCB0byBhZGQgdG8gdGhlIGNvbXBvc2VkIHZhbHVlXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gY29tcG9zZWRGcm9tS2V5c1xuICogQGNhdGVnb3J5IFByb3BlcnR5RGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcG9zZWRGcm9tS2V5cyhcbiAgYXJnczogc3RyaW5nW10sXG4gIHNlcGFyYXRvcjogc3RyaW5nID0gRGVmYXVsdFNlcGFyYXRvcixcbiAgaGFzaDogYm9vbGVhbiA9IGZhbHNlLFxuICBwcmVmaXggPSBcIlwiLFxuICBzdWZmaXggPSBcIlwiXG4pIHtcbiAgcmV0dXJuIGNvbXBvc2VkRnJvbShhcmdzLCBoYXNoLCBzZXBhcmF0b3IsIFwia2V5c1wiLCBwcmVmaXgsIHN1ZmZpeCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBkZWNvcmF0b3IgdGhhdCBjb21wb3NlcyBhIHByb3BlcnR5IHZhbHVlIGZyb20gcHJvcGVydHkgdmFsdWVzXG4gKiBAc3VtbWFyeSBEZWNvcmF0b3IgdGhhdCBnZW5lcmF0ZXMgYSBwcm9wZXJ0eSB2YWx1ZSBieSBqb2luaW5nIHRoZSB2YWx1ZXMgb2Ygb3RoZXIgcHJvcGVydGllc1xuICogQHBhcmFtIHtzdHJpbmdbXX0gYXJncyAtIFByb3BlcnR5IG5hbWVzIHdob3NlIHZhbHVlcyB3aWxsIGJlIGNvbXBvc2VkXG4gKiBAcGFyYW0ge3N0cmluZ30gW3NlcGFyYXRvcj1EZWZhdWx0U2VwYXJhdG9yXSAtIENoYXJhY3RlciB1c2VkIHRvIGpvaW4gdGhlIHByb3BlcnR5IHZhbHVlc1xuICogQHBhcmFtIHtib29sZWFufSBbaGFzaD1mYWxzZV0gLSBXaGV0aGVyIHRvIGhhc2ggdGhlIGNvbXBvc2VkIHJlc3VsdFxuICogQHBhcmFtIHtzdHJpbmd9IFtwcmVmaXg9XCJcIl0gLSBPcHRpb25hbCBwcmVmaXggdG8gYWRkIHRvIHRoZSBjb21wb3NlZCB2YWx1ZVxuICogQHBhcmFtIHtzdHJpbmd9IFtzdWZmaXg9XCJcIl0gLSBPcHRpb25hbCBzdWZmaXggdG8gYWRkIHRvIHRoZSBjb21wb3NlZCB2YWx1ZVxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIGNvbXBvc2VkXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHlEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wb3NlZChcbiAgYXJnczogc3RyaW5nW10sXG4gIHNlcGFyYXRvcjogc3RyaW5nID0gRGVmYXVsdFNlcGFyYXRvcixcbiAgaGFzaDogYm9vbGVhbiA9IGZhbHNlLFxuICBwcmVmaXggPSBcIlwiLFxuICBzdWZmaXggPSBcIlwiXG4pIHtcbiAgcmV0dXJuIGNvbXBvc2VkRnJvbShhcmdzLCBoYXNoLCBzZXBhcmF0b3IsIFwidmFsdWVzXCIsIHByZWZpeCwgc3VmZml4KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgdXBkYXRlcyBhIHZlcnNpb24gcHJvcGVydHkgZHVyaW5nIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IEZhY3RvcnkgZnVuY3Rpb24gdGhhdCBnZW5lcmF0ZXMgYSBjYWxsYmFjayBmb3IgaW5jcmVtZW50aW5nIHZlcnNpb24gbnVtYmVyc1xuICogQHBhcmFtIHtDcnVkT3BlcmF0aW9uc30gb3BlcmF0aW9uIC0gVGhlIHR5cGUgb2Ygb3BlcmF0aW9uIChDUkVBVEUgb3IgVVBEQVRFKVxuICogQHJldHVybiB7RnVuY3Rpb259IEEgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB1cGRhdGVzIHRoZSB2ZXJzaW9uIHByb3BlcnR5XG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFR5cGUgZXh0ZW5kaW5nIElSZXBvc2l0b3J5XG4gKiBAdGVtcGxhdGUgViAtIFR5cGUgZm9yIG1ldGFkYXRhXG4gKiBAdGVtcGxhdGUgRiAtIFR5cGUgZXh0ZW5kaW5nIFJlcG9zaXRvcnlGbGFnc1xuICogQHRlbXBsYXRlIEMgLSBUeXBlIGV4dGVuZGluZyBDb250ZXh0XG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNyZWF0ZVVwZGF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCB2ZXJzaW9uQ3JlYXRlVXBkYXRlXG4gKlxuICogICBDYWxsZXItPj52ZXJzaW9uQ3JlYXRlVXBkYXRlOiBvcGVyYXRpb25cbiAqICAgdmVyc2lvbkNyZWF0ZVVwZGF0ZS0tPj5DYWxsZXI6IGNhbGxiYWNrIGZ1bmN0aW9uXG4gKiAgIE5vdGUgb3ZlciBDYWxsZXIsdmVyc2lvbkNyZWF0ZVVwZGF0ZTogV2hlbiBjYWxsYmFjayBpcyBleGVjdXRlZDpcbiAqICAgQ2FsbGVyLT4+dmVyc2lvbkNyZWF0ZVVwZGF0ZTogY29udGV4dCwgZGF0YSwga2V5LCBtb2RlbFxuICogICBhbHQgb3BlcmF0aW9uIGlzIENSRUFURVxuICogICAgIHZlcnNpb25DcmVhdGVVcGRhdGUtPj52ZXJzaW9uQ3JlYXRlVXBkYXRlOiBzZXQgdmVyc2lvbiB0byAxXG4gKiAgIGVsc2Ugb3BlcmF0aW9uIGlzIFVQREFURVxuICogICAgIHZlcnNpb25DcmVhdGVVcGRhdGUtPj52ZXJzaW9uQ3JlYXRlVXBkYXRlOiBpbmNyZW1lbnQgdmVyc2lvblxuICogICBlbHNlIGludmFsaWQgb3BlcmF0aW9uXG4gKiAgICAgdmVyc2lvbkNyZWF0ZVVwZGF0ZS0+PnZlcnNpb25DcmVhdGVVcGRhdGU6IHRocm93IGVycm9yXG4gKiAgIGVuZFxuICogICB2ZXJzaW9uQ3JlYXRlVXBkYXRlLS0+PkNhbGxlcjogdm9pZFxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyc2lvbkNyZWF0ZVVwZGF0ZShvcGVyYXRpb246IENydWRPcGVyYXRpb25zKSB7XG4gIHJldHVybiBmdW5jdGlvbiB2ZXJzaW9uQ3JlYXRlVXBkYXRlPFxuICAgIE0gZXh0ZW5kcyBNb2RlbCxcbiAgICBSIGV4dGVuZHMgSVJlcG9zaXRvcnk8TSwgRiwgQz4sXG4gICAgViBleHRlbmRzIG9iamVjdCxcbiAgICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzID0gUmVwb3NpdG9yeUZsYWdzLFxuICAgIEMgZXh0ZW5kcyBDb250ZXh0PEY+ID0gQ29udGV4dDxGPixcbiAgPih0aGlzOiBSLCBjb250ZXh0OiBDLCBkYXRhOiBWLCBrZXk6IGtleW9mIE0sIG1vZGVsOiBNKSB7XG4gICAgdHJ5IHtcbiAgICAgIHN3aXRjaCAob3BlcmF0aW9uKSB7XG4gICAgICAgIGNhc2UgT3BlcmF0aW9uS2V5cy5DUkVBVEU6XG4gICAgICAgICAgKG1vZGVsIGFzIGFueSlba2V5XSA9IDE7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgT3BlcmF0aW9uS2V5cy5VUERBVEU6XG4gICAgICAgICAgKG1vZGVsIGFzIGFueSlba2V5XSsrO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBJbnZhbGlkIG9wZXJhdGlvbjogJHtvcGVyYXRpb259YCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYEZhaWxlZCB0byB1cGRhdGUgdmVyc2lvbjogJHtlfWApO1xuICAgIH1cbiAgfTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGRlY29yYXRvciBmb3IgdmVyc2lvbmluZyBhIHByb3BlcnR5IGluIGEgbW9kZWxcbiAqIEBzdW1tYXJ5IFRoaXMgZGVjb3JhdG9yIGFwcGxpZXMgbXVsdGlwbGUgc3ViLWRlY29yYXRvcnMgdG8gaGFuZGxlIHZlcnNpb24gbWFuYWdlbWVudCBkdXJpbmcgY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgY29tcG9zaXRlIGRlY29yYXRvciB0aGF0IHNldHMgdGhlIHR5cGUgdG8gTnVtYmVyLCBtYW5hZ2VzIHZlcnNpb24gdXBkYXRlcywgYW5kIGFkZHMgdmVyc2lvbmluZyBtZXRhZGF0YVxuICogQGZ1bmN0aW9uIHZlcnNpb25cbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eURlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZlcnNpb24oKSB7XG4gIGNvbnN0IGtleSA9IFJlcG9zaXRvcnkua2V5KERCS2V5cy5WRVJTSU9OKTtcbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKGtleSlcbiAgICAuZGVmaW5lKFxuICAgICAgdHlwZShOdW1iZXIubmFtZSksXG4gICAgICBvbkNyZWF0ZSh2ZXJzaW9uQ3JlYXRlVXBkYXRlKE9wZXJhdGlvbktleXMuQ1JFQVRFKSksXG4gICAgICBvblVwZGF0ZSh2ZXJzaW9uQ3JlYXRlVXBkYXRlKE9wZXJhdGlvbktleXMuVVBEQVRFKSksXG4gICAgICBwcm9wTWV0YWRhdGEoa2V5LCB0cnVlKVxuICAgIClcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGRlY29yYXRvciB0aGF0IG1hcmtzIGEgcHJvcGVydHkgYXMgdHJhbnNpZW50XG4gKiBAc3VtbWFyeSBEZWNvcmF0b3IgdGhhdCBpbmRpY2F0ZXMgYSBwcm9wZXJ0eSBzaG91bGQgbm90IGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2VcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiB0cmFuc2llbnRcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eURlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zaWVudCgpIHtcbiAgY29uc3Qga2V5ID0gUmVwb3NpdG9yeS5rZXkoREJLZXlzLlRSQU5TSUVOVCk7XG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihrZXkpXG4gICAgLmRlZmluZShmdW5jdGlvbiB0cmFuc2llbnQobW9kZWw6IGFueSwgYXR0cmlidXRlOiBhbnkpIHtcbiAgICAgIHByb3BNZXRhZGF0YShSZXBvc2l0b3J5LmtleShEQktleXMuVFJBTlNJRU5UKSwgdHJ1ZSkobW9kZWwsIGF0dHJpYnV0ZSk7XG4gICAgICBwcm9wTWV0YWRhdGEoUmVwb3NpdG9yeS5rZXkoREJLZXlzLlRSQU5TSUVOVCksIHRydWUpKG1vZGVsLmNvbnN0cnVjdG9yKTtcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuIl19