UNPKG

@decaf-ts/decorator-validation

Version:
548 lines 67.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validationMetadata = validationMetadata; exports.async = async; exports.required = required; exports.min = min; exports.max = max; exports.step = step; exports.minlength = minlength; exports.maxlength = maxlength; exports.pattern = pattern; exports.email = email; exports.url = url; exports.type = type; exports.date = date; exports.password = password; exports.list = list; exports.set = set; exports.eq = eq; exports.diff = diff; exports.lt = lt; exports.lte = lte; exports.gt = gt; exports.gte = gte; require("reflect-metadata"); const constants_1 = require("./Validators/constants.cjs"); const strings_1 = require("./../utils/strings.cjs"); const dates_1 = require("./../utils/dates.cjs"); const decorators_1 = require("./../utils/decorators.cjs"); const Validation_1 = require("./Validation.cjs"); const Decoration_1 = require("./../utils/Decoration.cjs"); const reflection_1 = require("@decaf-ts/reflection"); const constants_2 = require("./../constants/index.cjs"); /** * @description Combined property decorator factory for metadata and attribute marking * @summary Creates a decorator that both marks a property as a model attribute and assigns metadata to it * * @template V * @param {PropertyDecorator} decorator - The metadata key * @param {string} key - The metadata key * @param {V} value - The metadata value to associate with the property * @return {Function} - Combined decorator function * @function validationMetadata * @category Property Decorators */ function validationMetadata(decorator, key, value) { Validation_1.Validation.registerDecorator(key, decorator); return (0, reflection_1.apply)((0, decorators_1.propMetadata)(key, value)); } function async() { return (model) => { if (!Object.prototype.hasOwnProperty.call(model, constants_2.ASYNC_META_KEY)) model[constants_2.ASYNC_META_KEY] = true; }; } /** * @description Property decorator that marks a field as required * @summary Marks the property as required, causing validation to fail if the property is undefined, null, or empty. * Validators to validate a decorated property must use key {@link ValidationKeys#REQUIRED}. * This decorator is commonly used as the first validation step for important fields. * * @param {string} [message] - The error message to display when validation fails. Defaults to {@link DEFAULT_ERROR_MESSAGES#REQUIRED} * @return {PropertyDecorator} A decorator function that can be applied to class properties * * @function required * @category Property Decorators * * @example * ```typescript * class User { * @required() * username: string; * * @required("Email address is mandatory") * email: string; * } * ``` */ function required(message = constants_1.DEFAULT_ERROR_MESSAGES.REQUIRED) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.REQUIRED); const meta = { message: message, description: `defines the attribute as required`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(required, key, meta)) .apply(); } /** * @description Property decorator that enforces a minimum value constraint * @summary Defines a minimum value for the property, causing validation to fail if the property value is less than the specified minimum. * Validators to validate a decorated property must use key {@link ValidationKeys#MIN}. * This decorator works with numeric values and dates. * * @param {number | Date | string} value - The minimum value allowed. For dates, can be a Date object or a string that can be converted to a date * @param {string} [message] - The error message to display when validation fails. Defaults to {@link DEFAULT_ERROR_MESSAGES#MIN} * @return {PropertyDecorator} A decorator function that can be applied to class properties * * @function min * @category Property Decorators * * @example * ```typescript * class Product { * @min(0) * price: number; * * @min(new Date(2023, 0, 1), "Date must be after January 1, 2023") * releaseDate: Date; * } * ``` */ function min(value, message = constants_1.DEFAULT_ERROR_MESSAGES.MIN) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.MIN); const meta = { [constants_1.ValidationKeys.MIN]: value, message: message, types: [Number.name, Date.name], description: `defines the max value of the attribute as ${value} (applies to numbers or Dates)`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(min, key, meta)) .apply(); } /** * @summary Defines a maximum value for the property * @description Validators to validate a decorated property must use key {@link ValidationKeys#MAX} * * @param {number | Date} value * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#MAX} * * @function max * @category Property Decorators */ function max(value, message = constants_1.DEFAULT_ERROR_MESSAGES.MAX) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.MAX); const meta = { [constants_1.ValidationKeys.MAX]: value, message: message, types: [Number.name, Date.name], description: `defines the max value of the attribute as ${value} (applies to numbers or Dates)`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(max, key, meta)) .apply(); } /** * @summary Defines a step value for the property * @description Validators to validate a decorated property must use key {@link ValidationKeys#STEP} * * @param {number} value * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#STEP} * * @function step * @category Property Decorators */ function step(value, message = constants_1.DEFAULT_ERROR_MESSAGES.STEP) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.STEP); const meta = { [constants_1.ValidationKeys.STEP]: value, message: message, types: [Number.name], description: `defines the step of the attribute as ${value}`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(step, key, meta)) .apply(); } /** * @summary Defines a minimum length for the property * @description Validators to validate a decorated property must use key {@link ValidationKeys#MIN_LENGTH} * * @param {string} value * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#MIN_LENGTH} * * @function minlength * @category Property Decorators */ function minlength(value, message = constants_1.DEFAULT_ERROR_MESSAGES.MIN_LENGTH) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.MIN_LENGTH); const meta = { [constants_1.ValidationKeys.MIN_LENGTH]: value, message: message, types: [String.name, Array.name, Set.name], description: `defines the min length of the attribute as ${value} (applies to strings or lists)`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(minlength, key, meta)) .apply(); } /** * @summary Defines a maximum length for the property * @description Validators to validate a decorated property must use key {@link ValidationKeys#MAX_LENGTH} * * @param {string} value * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#MAX_LENGTH} * * @function maxlength * @category Property Decorators */ function maxlength(value, message = constants_1.DEFAULT_ERROR_MESSAGES.MAX_LENGTH) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.MAX_LENGTH); const meta = { [constants_1.ValidationKeys.MAX_LENGTH]: value, message: message, types: [String.name, Array.name, Set.name], description: `defines the max length of the attribute as ${value} (applies to strings or lists)`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(maxlength, key, meta)) .apply(); } /** * @summary Defines a RegExp pattern the property must respect * @description Validators to validate a decorated property must use key {@link ValidationKeys#PATTERN} * * @param {string} value * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#PATTERN} * * @function pattern * @category Property Decorators */ function pattern(value, message = constants_1.DEFAULT_ERROR_MESSAGES.PATTERN) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.PATTERN); const meta = { [constants_1.ValidationKeys.PATTERN]: typeof value === "string" ? value : value.toString(), message: message, types: [String.name], description: `assigns the ${value === "string" ? value : value.toString()} pattern to the attribute`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(pattern, key, meta)) .apply(); } /** * @summary Defines the property as an email * @description Validators to validate a decorated property must use key {@link ValidationKeys#EMAIL} * * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#EMAIL} * * @function email * @category Property Decorators */ function email(message = constants_1.DEFAULT_ERROR_MESSAGES.EMAIL) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.EMAIL); const meta = { [constants_1.ValidationKeys.PATTERN]: constants_1.DEFAULT_PATTERNS.EMAIL.toString(), message: message, types: [String.name], description: "marks the attribute as an email", async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(email, key, meta)) .apply(); } /** * @summary Defines the property as an URL * @description Validators to validate a decorated property must use key {@link ValidationKeys#URL} * * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#URL} * * @function url * @category Property Decorators */ function url(message = constants_1.DEFAULT_ERROR_MESSAGES.URL) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.URL); const meta = { [constants_1.ValidationKeys.PATTERN]: constants_1.DEFAULT_PATTERNS.URL.toString(), message: message, types: [String.name], description: "marks the attribute as an url", async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(url, key, meta)) .apply(); } /** * @summary Enforces type verification * @description Validators to validate a decorated property must use key {@link ValidationKeys#TYPE} * * @param {string[] | string} types accepted types * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#TYPE} * * @function type * @category Property Decorators */ function type(types, message = constants_1.DEFAULT_ERROR_MESSAGES.TYPE) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.TYPE); const meta = { customTypes: types, message: message, description: "defines the accepted types for the attribute", async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(type, key, meta)) .apply(); } /** * @summary Date Handler Decorator * @description Validators to validate a decorated property must use key {@link ValidationKeys#DATE} * * Will enforce serialization according to the selected format * * @param {string} format accepted format according to {@link formatDate} * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#DATE} * * @function date * * @category Property Decorators */ function date(format = "dd/MM/yyyy", message = constants_1.DEFAULT_ERROR_MESSAGES.DATE) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.DATE); const meta = { [constants_1.ValidationKeys.FORMAT]: format, message: message, types: [Date.name], description: `defines the attribute as a date with the format ${format}`, async: false, }; const dateDec = (target, propertyKey) => { validationMetadata(date, key, meta)(target, propertyKey); const values = new WeakMap(); Object.defineProperty(target, propertyKey, { configurable: false, set(newValue) { const descriptor = Object.getOwnPropertyDescriptor(this, propertyKey); if (!descriptor || descriptor.configurable) Object.defineProperty(this, propertyKey, { enumerable: true, configurable: false, get: () => values.get(this), set: (newValue) => { let val; try { val = (0, dates_1.parseDate)(format, newValue); values.set(this, val); } catch (e) { console.error((0, strings_1.sf)("Failed to parse date: {0}", e.message || e)); } }, }); this[propertyKey] = newValue; }, get() { console.log("here"); }, }); }; return Decoration_1.Decoration.for(key).define(dateDec).apply(); } /** * @summary Password Handler Decorator * @description Validators to validate a decorated property must use key {@link ValidationKeys#PASSWORD} * * @param {RegExp} [pattern] defaults to {@link DEFAULT_PATTERNS#CHAR8_ONE_OF_EACH} * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES#PASSWORD} * * @function password * * @category Property Decorators */ function password(pattern = constants_1.DEFAULT_PATTERNS.PASSWORD.CHAR8_ONE_OF_EACH, message = constants_1.DEFAULT_ERROR_MESSAGES.PASSWORD) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.PASSWORD); const meta = { [constants_1.ValidationKeys.PATTERN]: pattern.toString(), message: message, types: [String.name], description: `attribute as a password`, async: false, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(password, key, meta)) .apply(); } /** * @summary List Decorator * @description Also sets the {@link type} to the provided collection * * @param {ModelConstructor} clazz * @param {string} [collection] The collection being used. defaults to Array * @param {string} [message] defaults to {@link DEFAULT_ERROR_MESSAGES#LIST} * * @function list * * @category Property Decorators */ function list(clazz, collection = "Array", message = constants_1.DEFAULT_ERROR_MESSAGES.LIST) { const key = Validation_1.Validation.key(constants_1.ValidationKeys.LIST); const meta = { clazz: Array.isArray(clazz) ? clazz.map((c) => c.name) : [clazz.name], type: collection, message: message, async: false, description: `defines the attribute as a ${collection} of ${clazz.name}`, }; return Decoration_1.Decoration.for(key) .define(validationMetadata(list, key, meta)) .apply(); } /** * @summary Set Decorator * @description Wrapper for {@link list} with the 'Set' Collection * * @param {ModelConstructor} clazz * @param {string} [message] defaults to {@link DEFAULT_ERROR_MESSAGES#LIST} * * @function set * * @category Property Decorators */ function set(clazz, message = constants_1.DEFAULT_ERROR_MESSAGES.LIST) { return list(clazz, "Set", message); } /** * @summary Declares that the decorated property must be equal to another specified property. * @description Applies the {@link ValidationKeys.EQUALS} validator to ensure the decorated value matches the value of the given property. * * @param {string} propertyToCompare - The name of the property to compare equality against. * @param {string} [message=DEFAULT_ERROR_MESSAGES.EQUALS] - Custom error message to return if validation fails. * * @returns {PropertyDecorator} A property decorator used to register the equality validation metadata. * * @function eq * @category Property Decorators */ function eq(propertyToCompare, message = constants_1.DEFAULT_ERROR_MESSAGES.EQUALS) { const options = { message: message, [constants_1.ValidationKeys.EQUALS]: propertyToCompare, description: `defines attribute as equal to ${propertyToCompare}`, }; return validationMetadata(eq, Validation_1.Validation.key(constants_1.ValidationKeys.EQUALS), { ...options, async: false }); } /** * @summary Declares that the decorated property must be different from another specified property. * @description Applies the {@link ValidationKeys.DIFF} validator to ensure the decorated value is different from the value of the given property. * * @param {string} propertyToCompare - The name of the property to compare difference against. * @param {string} [message=DEFAULT_ERROR_MESSAGES.DIFF] - Custom error message to return if validation fails. * * @returns {PropertyDecorator} A property decorator used to register the difference validation metadata. * * @function diff * @category Property Decorators */ function diff(propertyToCompare, message = constants_1.DEFAULT_ERROR_MESSAGES.DIFF) { const options = { message: message, [constants_1.ValidationKeys.DIFF]: propertyToCompare, description: `defines attribute as different to ${propertyToCompare}`, }; return validationMetadata(diff, Validation_1.Validation.key(constants_1.ValidationKeys.DIFF), { ...options, async: false, }); } /** * @summary Declares that the decorated property must be less than another specified property. * @description Applies the {@link ValidationKeys.LESS_THAN} validator to ensure the decorated value is less than the value of the given property. * * @param {string} propertyToCompare - The name of the property to compare against. * @param {string} [message=DEFAULT_ERROR_MESSAGES.LESS_THAN] - Custom error message to return if validation fails. * * @returns {PropertyDecorator} A property decorator used to register the less than validation metadata. * * @function lt * @category Property Decorators */ function lt(propertyToCompare, message = constants_1.DEFAULT_ERROR_MESSAGES.LESS_THAN) { const options = { message: message, [constants_1.ValidationKeys.LESS_THAN]: propertyToCompare, description: `defines attribute as less than to ${propertyToCompare}`, }; return validationMetadata(lt, Validation_1.Validation.key(constants_1.ValidationKeys.LESS_THAN), { ...options, async: false }); } /** * @summary Declares that the decorated property must be equal or less than another specified property. * @description Applies the {@link ValidationKeys.LESS_THAN_OR_EQUAL} validator to ensure the decorated value is equal or less than the value of the given property. * * @param {string} propertyToCompare - The name of the property to compare against. * @param {string} [message=DEFAULT_ERROR_MESSAGES.LESS_THAN_OR_EQUAL] - Custom error message to return if validation fails. * * @returns {PropertyDecorator} A property decorator used to register the less than or equal validation metadata. * * @function lte * @category Property Decorators */ function lte(propertyToCompare, message = constants_1.DEFAULT_ERROR_MESSAGES.LESS_THAN_OR_EQUAL) { const options = { message: message, [constants_1.ValidationKeys.LESS_THAN_OR_EQUAL]: propertyToCompare, description: `defines attribute as less or equal to ${propertyToCompare}`, }; return validationMetadata(lte, Validation_1.Validation.key(constants_1.ValidationKeys.LESS_THAN_OR_EQUAL), { ...options, async: false }); } /** * @summary Declares that the decorated property must be greater than another specified property. * @description Applies the {@link ValidationKeys.GREATER_THAN} validator to ensure the decorated value is greater than the value of the given property. * * @param {string} propertyToCompare - The name of the property to compare against. * @param {string} [message=DEFAULT_ERROR_MESSAGES.GREATER_THAN] - Custom error message to return if validation fails. * * @returns {PropertyDecorator} A property decorator used to register the greater than validation metadata. * * @function gt * @category Property Decorators */ function gt(propertyToCompare, message = constants_1.DEFAULT_ERROR_MESSAGES.GREATER_THAN) { const options = { message: message, [constants_1.ValidationKeys.GREATER_THAN]: propertyToCompare, description: `defines attribute as greater than ${propertyToCompare}`, }; return validationMetadata(gt, Validation_1.Validation.key(constants_1.ValidationKeys.GREATER_THAN), { ...options, async: false }); } /** * @summary Declares that the decorated property must be equal or greater than another specified property. * @description Applies the {@link ValidationKeys.GREATER_THAN_OR_EQUAL} validator to ensure the decorated value is equal or greater than the value of the given property. * * @param {string} propertyToCompare - The name of the property to compare against. * @param {string} [message=DEFAULT_ERROR_MESSAGES.GREATER_THAN_OR_EQUAL] - Custom error message to return if validation fails. * * @returns {PropertyDecorator} A property decorator used to register the greater than or equal validation metadata. * * @function gte * @category Property Decorators */ function gte(propertyToCompare, message = constants_1.DEFAULT_ERROR_MESSAGES.GREATER_THAN_OR_EQUAL) { const options = { message: message, [constants_1.ValidationKeys.GREATER_THAN_OR_EQUAL]: propertyToCompare, description: `defines attribute as greater or equal to ${propertyToCompare}`, }; return validationMetadata(gte, Validation_1.Validation.key(constants_1.ValidationKeys.GREATER_THAN_OR_EQUAL), { ...options, async: false }); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVjb3JhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92YWxpZGF0aW9uL2RlY29yYXRvcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE2Q0EsZ0RBR0M7QUFFRCxzQkFLQztBQXlCRCw0QkFVQztBQTBCRCxrQkFlQztBQVlELGtCQWVDO0FBWUQsb0JBZUM7QUFZRCw4QkFlQztBQVlELDhCQWVDO0FBWUQsMEJBZ0JDO0FBV0Qsc0JBWUM7QUFXRCxrQkFZQztBQWdCRCxvQkFjQztBQW1CRCxvQkE0Q0M7QUFhRCw0QkFlQztBQWtCRCxvQkFnQkM7QUFhRCxrQkFLQztBQWNELGdCQWVDO0FBY0Qsb0JBa0JDO0FBY0QsZ0JBZUM7QUFjRCxrQkFlQztBQWNELGdCQWVDO0FBY0Qsa0JBZUM7QUF2cEJELDRCQUEwQjtBQW1CMUIsMERBSWdDO0FBQ2hDLG9EQUFzQztBQUV0QyxnREFBMkM7QUFDM0MsMERBQW1EO0FBQ25ELGlEQUEwQztBQUMxQywwREFBaUQ7QUFDakQscURBQTZDO0FBQzdDLHdEQUE4QztBQUU5Qzs7Ozs7Ozs7Ozs7R0FXRztBQUNILFNBQWdCLGtCQUFrQixDQUFJLFNBQWMsRUFBRSxHQUFXLEVBQUUsS0FBUTtJQUN6RSx1QkFBVSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUM3QyxPQUFPLElBQUEsa0JBQUssRUFBQyxJQUFBLHlCQUFZLEVBQUksR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDNUMsQ0FBQztBQUVELFNBQWdCLEtBQUs7SUFDbkIsT0FBTyxDQUFDLEtBQWEsRUFBUSxFQUFFO1FBQzdCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLDBCQUFjLENBQUM7WUFDN0QsS0FBYSxDQUFDLDBCQUFjLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDMUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVE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QWtCLGtDQUFzQixDQUFDLFlBQVk7SUFFckQsTUFBTSxPQUFPLEdBQWdDO1FBQzNDLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLENBQUMsMEJBQWMsQ0FBQyxZQUFZLENBQUMsRUFBRSxpQkFBaUI7UUFDaEQsV0FBVyxFQUFFLHFDQUFxQyxpQkFBaUIsRUFBRTtLQUN0RSxDQUFDO0lBRUYsT0FBTyxrQkFBa0IsQ0FDdkIsRUFBRSxFQUNGLHVCQUFVLENBQUMsR0FBRyxDQUFDLDBCQUFjLENBQUMsWUFBWSxDQUFDLEVBQzNDLEVBQUUsR0FBRyxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBd0IsQ0FDbkQsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILFNBQWdCLEdBQUcsQ0FDakIsaUJBQXlCLEVBQ3pCLFVBQWtCLGtDQUFzQixDQUFDLHFCQUFxQjtJQUU5RCxNQUFNLE9BQU8sR0FBdUM7UUFDbEQsT0FBTyxFQUFFLE9BQU87UUFDaEIsQ0FBQywwQkFBYyxDQUFDLHFCQUFxQixDQUFDLEVBQUUsaUJBQWlCO1FBQ3pELFdBQVcsRUFBRSw0Q0FBNEMsaUJBQWlCLEVBQUU7S0FDN0UsQ0FBQztJQUVGLE9BQU8sa0JBQWtCLENBQ3ZCLEdBQUcsRUFDSCx1QkFBVSxDQUFDLEdBQUcsQ0FBQywwQkFBYyxDQUFDLHFCQUFxQixDQUFDLEVBQ3BELEVBQUUsR0FBRyxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBd0IsQ0FDbkQsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXCJyZWZsZWN0LW1ldGFkYXRhXCI7XG5pbXBvcnQge1xuICBEYXRlVmFsaWRhdG9yT3B0aW9ucyxcbiAgRGlmZlZhbGlkYXRvck9wdGlvbnMsXG4gIEVxdWFsc1ZhbGlkYXRvck9wdGlvbnMsXG4gIEdyZWF0ZXJUaGFuT3JFcXVhbFZhbGlkYXRvck9wdGlvbnMsXG4gIEdyZWF0ZXJUaGFuVmFsaWRhdG9yT3B0aW9ucyxcbiAgTGVzc1RoYW5PckVxdWFsVmFsaWRhdG9yT3B0aW9ucyxcbiAgTGVzc1RoYW5WYWxpZGF0b3JPcHRpb25zLFxuICBMaXN0VmFsaWRhdG9yT3B0aW9ucyxcbiAgTWF4TGVuZ3RoVmFsaWRhdG9yT3B0aW9ucyxcbiAgTWF4VmFsaWRhdG9yT3B0aW9ucyxcbiAgTWluTGVuZ3RoVmFsaWRhdG9yT3B0aW9ucyxcbiAgTWluVmFsaWRhdG9yT3B0aW9ucyxcbiAgUGF0dGVyblZhbGlkYXRvck9wdGlvbnMsXG4gIFN0ZXBWYWxpZGF0b3JPcHRpb25zLFxuICBWYWxpZGF0aW9uTWV0YWRhdGEsXG4gIFZhbGlkYXRvck9wdGlvbnMsXG59IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQge1xuICBERUZBVUxUX0VSUk9SX01FU1NBR0VTLFxuICBERUZBVUxUX1BBVFRFUk5TLFxuICBWYWxpZGF0aW9uS2V5cyxcbn0gZnJvbSBcIi4vVmFsaWRhdG9ycy9jb25zdGFudHNcIjtcbmltcG9ydCB7IHNmIH0gZnJvbSBcIi4uL3V0aWxzL3N0cmluZ3NcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNb2RlbENvbnN0cnVjdG9yIH0gZnJvbSBcIi4uL21vZGVsL3R5cGVzXCI7XG5pbXBvcnQgeyBwYXJzZURhdGUgfSBmcm9tIFwiLi4vdXRpbHMvZGF0ZXNcIjtcbmltcG9ydCB7IHByb3BNZXRhZGF0YSB9IGZyb20gXCIuLi91dGlscy9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uIH0gZnJvbSBcIi4vVmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRGVjb3JhdGlvbiB9IGZyb20gXCIuLi91dGlscy9EZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBhcHBseSB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuaW1wb3J0IHsgQVNZTkNfTUVUQV9LRVkgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbWJpbmVkIHByb3BlcnR5IGRlY29yYXRvciBmYWN0b3J5IGZvciBtZXRhZGF0YSBhbmQgYXR0cmlidXRlIG1hcmtpbmdcbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBkZWNvcmF0b3IgdGhhdCBib3RoIG1hcmtzIGEgcHJvcGVydHkgYXMgYSBtb2RlbCBhdHRyaWJ1dGUgYW5kIGFzc2lnbnMgbWV0YWRhdGEgdG8gaXRcbiAqXG4gKiBAdGVtcGxhdGUgVlxuICogQHBhcmFtIHtQcm9wZXJ0eURlY29yYXRvcn0gZGVjb3JhdG9yIC0gVGhlIG1ldGFkYXRhIGtleVxuICogQHBhcmFtIHtzdHJpbmd9IGtleSAtIFRoZSBtZXRhZGF0YSBrZXlcbiAqIEBwYXJhbSB7Vn0gdmFsdWUgLSBUaGUgbWV0YWRhdGEgdmFsdWUgdG8gYXNzb2NpYXRlIHdpdGggdGhlIHByb3BlcnR5XG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gLSBDb21iaW5lZCBkZWNvcmF0b3IgZnVuY3Rpb25cbiAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uTWV0YWRhdGFcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0aW9uTWV0YWRhdGE8Vj4oZGVjb3JhdG9yOiBhbnksIGtleTogc3RyaW5nLCB2YWx1ZTogVikge1xuICBWYWxpZGF0aW9uLnJlZ2lzdGVyRGVjb3JhdG9yKGtleSwgZGVjb3JhdG9yKTtcbiAgcmV0dXJuIGFwcGx5KHByb3BNZXRhZGF0YTxWPihrZXksIHZhbHVlKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhc3luYygpIHtcbiAgcmV0dXJuIChtb2RlbDogb2JqZWN0KTogdm9pZCA9PiB7XG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobW9kZWwsIEFTWU5DX01FVEFfS0VZKSlcbiAgICAgIChtb2RlbCBhcyBhbnkpW0FTWU5DX01FVEFfS0VZXSA9IHRydWU7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFByb3BlcnR5IGRlY29yYXRvciB0aGF0IG1hcmtzIGEgZmllbGQgYXMgcmVxdWlyZWRcbiAqIEBzdW1tYXJ5IE1hcmtzIHRoZSBwcm9wZXJ0eSBhcyByZXF1aXJlZCwgY2F1c2luZyB2YWxpZGF0aW9uIHRvIGZhaWwgaWYgdGhlIHByb3BlcnR5IGlzIHVuZGVmaW5lZCwgbnVsbCwgb3IgZW1wdHkuXG4gKiBWYWxpZGF0b3JzIHRvIHZhbGlkYXRlIGEgZGVjb3JhdGVkIHByb3BlcnR5IG11c3QgdXNlIGtleSB7QGxpbmsgVmFsaWRhdGlvbktleXMjUkVRVUlSRUR9LlxuICogVGhpcyBkZWNvcmF0b3IgaXMgY29tbW9ubHkgdXNlZCBhcyB0aGUgZmlyc3QgdmFsaWRhdGlvbiBzdGVwIGZvciBpbXBvcnRhbnQgZmllbGRzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBkaXNwbGF5IHdoZW4gdmFsaWRhdGlvbiBmYWlscy4gRGVmYXVsdHMgdG8ge0BsaW5rIERFRkFVTFRfRVJST1JfTUVTU0FHRVMjUkVRVUlSRUR9XG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgZnVuY3Rpb24gdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKlxuICogQGZ1bmN0aW9uIHJlcXVpcmVkXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjbGFzcyBVc2VyIHtcbiAqICAgQHJlcXVpcmVkKClcbiAqICAgdXNlcm5hbWU6IHN0cmluZztcbiAqXG4gKiAgIEByZXF1aXJlZChcIkVtYWlsIGFkZHJlc3MgaXMgbWFuZGF0b3J5XCIpXG4gKiAgIGVtYWlsOiBzdHJpbmc7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVkKG1lc3NhZ2U6IHN0cmluZyA9IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuUkVRVUlSRUQpIHtcbiAgY29uc3Qga2V5ID0gVmFsaWRhdGlvbi5rZXkoVmFsaWRhdGlvbktleXMuUkVRVUlSRUQpO1xuICBjb25zdCBtZXRhOiBWYWxpZGF0b3JPcHRpb25zID0ge1xuICAgIG1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgZGVzY3JpcHRpb246IGBkZWZpbmVzIHRoZSBhdHRyaWJ1dGUgYXMgcmVxdWlyZWRgLFxuICAgIGFzeW5jOiBmYWxzZSxcbiAgfTtcbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKGtleSlcbiAgICAuZGVmaW5lKHZhbGlkYXRpb25NZXRhZGF0YTxWYWxpZGF0b3JPcHRpb25zPihyZXF1aXJlZCwga2V5LCBtZXRhKSlcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUHJvcGVydHkgZGVjb3JhdG9yIHRoYXQgZW5mb3JjZXMgYSBtaW5pbXVtIHZhbHVlIGNvbnN0cmFpbnRcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBtaW5pbXVtIHZhbHVlIGZvciB0aGUgcHJvcGVydHksIGNhdXNpbmcgdmFsaWRhdGlvbiB0byBmYWlsIGlmIHRoZSBwcm9wZXJ0eSB2YWx1ZSBpcyBsZXNzIHRoYW4gdGhlIHNwZWNpZmllZCBtaW5pbXVtLlxuICogVmFsaWRhdG9ycyB0byB2YWxpZGF0ZSBhIGRlY29yYXRlZCBwcm9wZXJ0eSBtdXN0IHVzZSBrZXkge0BsaW5rIFZhbGlkYXRpb25LZXlzI01JTn0uXG4gKiBUaGlzIGRlY29yYXRvciB3b3JrcyB3aXRoIG51bWVyaWMgdmFsdWVzIGFuZCBkYXRlcy5cbiAqXG4gKiBAcGFyYW0ge251bWJlciB8IERhdGUgfCBzdHJpbmd9IHZhbHVlIC0gVGhlIG1pbmltdW0gdmFsdWUgYWxsb3dlZC4gRm9yIGRhdGVzLCBjYW4gYmUgYSBEYXRlIG9iamVjdCBvciBhIHN0cmluZyB0aGF0IGNhbiBiZSBjb252ZXJ0ZWQgdG8gYSBkYXRlXG4gKiBAcGFyYW0ge3N0cmluZ30gW21lc3NhZ2VdIC0gVGhlIGVycm9yIG1lc3NhZ2UgdG8gZGlzcGxheSB3aGVuIHZhbGlkYXRpb24gZmFpbHMuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX0VSUk9SX01FU1NBR0VTI01JTn1cbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciBmdW5jdGlvbiB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqXG4gKiBAZnVuY3Rpb24gbWluXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjbGFzcyBQcm9kdWN0IHtcbiAqICAgQG1pbigwKVxuICogICBwcmljZTogbnVtYmVyO1xuICpcbiAqICAgQG1pbihuZXcgRGF0ZSgyMDIzLCAwLCAxKSwgXCJEYXRlIG11c3QgYmUgYWZ0ZXIgSmFudWFyeSAxLCAyMDIzXCIpXG4gKiAgIHJlbGVhc2VEYXRlOiBEYXRlO1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtaW4oXG4gIHZhbHVlOiBudW1iZXIgfCBEYXRlIHwgc3RyaW5nLFxuICBtZXNzYWdlOiBzdHJpbmcgPSBERUZBVUxUX0VSUk9SX01FU1NBR0VTLk1JTlxuKSB7XG4gIGNvbnN0IGtleSA9IFZhbGlkYXRpb24ua2V5KFZhbGlkYXRpb25LZXlzLk1JTik7XG4gIGNvbnN0IG1ldGE6IE1pblZhbGlkYXRvck9wdGlvbnMgPSB7XG4gICAgW1ZhbGlkYXRpb25LZXlzLk1JTl06IHZhbHVlLFxuICAgIG1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgdHlwZXM6IFtOdW1iZXIubmFtZSwgRGF0ZS5uYW1lXSxcbiAgICBkZXNjcmlwdGlvbjogYGRlZmluZXMgdGhlIG1heCB2YWx1ZSBvZiB0aGUgYXR0cmlidXRlIGFzICR7dmFsdWV9IChhcHBsaWVzIHRvIG51bWJlcnMgb3IgRGF0ZXMpYCxcbiAgICBhc3luYzogZmFsc2UsXG4gIH07XG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihrZXkpXG4gICAgLmRlZmluZSh2YWxpZGF0aW9uTWV0YWRhdGE8TWluVmFsaWRhdG9yT3B0aW9ucz4obWluLCBrZXksIG1ldGEpKVxuICAgIC5hcHBseSgpO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBtYXhpbXVtIHZhbHVlIGZvciB0aGUgcHJvcGVydHlcbiAqIEBkZXNjcmlwdGlvbiBWYWxpZGF0b3JzIHRvIHZhbGlkYXRlIGEgZGVjb3JhdGVkIHByb3BlcnR5IG11c3QgdXNlIGtleSB7QGxpbmsgVmFsaWRhdGlvbktleXMjTUFYfVxuICpcbiAqIEBwYXJhbSB7bnVtYmVyIHwgRGF0ZX0gdmFsdWVcbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gdGhlIGVycm9yIG1lc3NhZ2UuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX0VSUk9SX01FU1NBR0VTI01BWH1cbiAqXG4gKiBAZnVuY3Rpb24gbWF4XG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gbWF4KFxuICB2YWx1ZTogbnVtYmVyIHwgRGF0ZSB8IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nID0gREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5NQVhcbikge1xuICBjb25zdCBrZXkgPSBWYWxpZGF0aW9uLmtleShWYWxpZGF0aW9uS2V5cy5NQVgpO1xuICBjb25zdCBtZXRhOiBNYXhWYWxpZGF0b3JPcHRpb25zID0ge1xuICAgIFtWYWxpZGF0aW9uS2V5cy5NQVhdOiB2YWx1ZSxcbiAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgIHR5cGVzOiBbTnVtYmVyLm5hbWUsIERhdGUubmFtZV0sXG4gICAgZGVzY3JpcHRpb246IGBkZWZpbmVzIHRoZSBtYXggdmFsdWUgb2YgdGhlIGF0dHJpYnV0ZSBhcyAke3ZhbHVlfSAoYXBwbGllcyB0byBudW1iZXJzIG9yIERhdGVzKWAsXG4gICAgYXN5bmM6IGZhbHNlLFxuICB9O1xuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUodmFsaWRhdGlvbk1ldGFkYXRhPE1heFZhbGlkYXRvck9wdGlvbnM+KG1heCwga2V5LCBtZXRhKSlcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGEgc3RlcCB2YWx1ZSBmb3IgdGhlIHByb3BlcnR5XG4gKiBAZGVzY3JpcHRpb24gVmFsaWRhdG9ycyB0byB2YWxpZGF0ZSBhIGRlY29yYXRlZCBwcm9wZXJ0eSBtdXN0IHVzZSBrZXkge0BsaW5rIFZhbGlkYXRpb25LZXlzI1NURVB9XG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlXG4gKiBAcGFyYW0ge3N0cmluZ30gW21lc3NhZ2VdIHRoZSBlcnJvciBtZXNzYWdlLiBEZWZhdWx0cyB0byB7QGxpbmsgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyNTVEVQfVxuICpcbiAqIEBmdW5jdGlvbiBzdGVwXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gc3RlcChcbiAgdmFsdWU6IG51bWJlcixcbiAgbWVzc2FnZTogc3RyaW5nID0gREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5TVEVQXG4pIHtcbiAgY29uc3Qga2V5ID0gVmFsaWRhdGlvbi5rZXkoVmFsaWRhdGlvbktleXMuU1RFUCk7XG4gIGNvbnN0IG1ldGE6IFN0ZXBWYWxpZGF0b3JPcHRpb25zID0ge1xuICAgIFtWYWxpZGF0aW9uS2V5cy5TVEVQXTogdmFsdWUsXG4gICAgbWVzc2FnZTogbWVzc2FnZSxcbiAgICB0eXBlczogW051bWJlci5uYW1lXSxcbiAgICBkZXNjcmlwdGlvbjogYGRlZmluZXMgdGhlIHN0ZXAgb2YgdGhlIGF0dHJpYnV0ZSBhcyAke3ZhbHVlfWAsXG4gICAgYXN5bmM6IGZhbHNlLFxuICB9O1xuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUodmFsaWRhdGlvbk1ldGFkYXRhPFN0ZXBWYWxpZGF0b3JPcHRpb25zPihzdGVwLCBrZXksIG1ldGEpKVxuICAgIC5hcHBseSgpO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBtaW5pbXVtIGxlbmd0aCBmb3IgdGhlIHByb3BlcnR5XG4gKiBAZGVzY3JpcHRpb24gVmFsaWRhdG9ycyB0byB2YWxpZGF0ZSBhIGRlY29yYXRlZCBwcm9wZXJ0eSBtdXN0IHVzZSBrZXkge0BsaW5rIFZhbGlkYXRpb25LZXlzI01JTl9MRU5HVEh9XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlXG4gKiBAcGFyYW0ge3N0cmluZ30gW21lc3NhZ2VdIHRoZSBlcnJvciBtZXNzYWdlLiBEZWZhdWx0cyB0byB7QGxpbmsgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyNNSU5fTEVOR1RIfVxuICpcbiAqIEBmdW5jdGlvbiBtaW5sZW5ndGhcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtaW5sZW5ndGgoXG4gIHZhbHVlOiBudW1iZXIsXG4gIG1lc3NhZ2U6IHN0cmluZyA9IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuTUlOX0xFTkdUSFxuKSB7XG4gIGNvbnN0IGtleSA9IFZhbGlkYXRpb24ua2V5KFZhbGlkYXRpb25LZXlzLk1JTl9MRU5HVEgpO1xuICBjb25zdCBtZXRhOiBNaW5MZW5ndGhWYWxpZGF0b3JPcHRpb25zID0ge1xuICAgIFtWYWxpZGF0aW9uS2V5cy5NSU5fTEVOR1RIXTogdmFsdWUsXG4gICAgbWVzc2FnZTogbWVzc2FnZSxcbiAgICB0eXBlczogW1N0cmluZy5uYW1lLCBBcnJheS5uYW1lLCBTZXQubmFtZV0sXG4gICAgZGVzY3JpcHRpb246IGBkZWZpbmVzIHRoZSBtaW4gbGVuZ3RoIG9mIHRoZSBhdHRyaWJ1dGUgYXMgJHt2YWx1ZX0gKGFwcGxpZXMgdG8gc3RyaW5ncyBvciBsaXN0cylgLFxuICAgIGFzeW5jOiBmYWxzZSxcbiAgfTtcbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKGtleSlcbiAgICAuZGVmaW5lKHZhbGlkYXRpb25NZXRhZGF0YTxNaW5MZW5ndGhWYWxpZGF0b3JPcHRpb25zPihtaW5sZW5ndGgsIGtleSwgbWV0YSkpXG4gICAgLmFwcGx5KCk7XG59XG5cbi8qKlxuICogQHN1bW1hcnkgRGVmaW5lcyBhIG1heGltdW0gbGVuZ3RoIGZvciB0aGUgcHJvcGVydHlcbiAqIEBkZXNjcmlwdGlvbiBWYWxpZGF0b3JzIHRvIHZhbGlkYXRlIGEgZGVjb3JhdGVkIHByb3BlcnR5IG11c3QgdXNlIGtleSB7QGxpbmsgVmFsaWRhdGlvbktleXMjTUFYX0xFTkdUSH1cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdmFsdWVcbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gdGhlIGVycm9yIG1lc3NhZ2UuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX0VSUk9SX01FU1NBR0VTI01BWF9MRU5HVEh9XG4gKlxuICogQGZ1bmN0aW9uIG1heGxlbmd0aFxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1heGxlbmd0aChcbiAgdmFsdWU6IG51bWJlcixcbiAgbWVzc2FnZTogc3RyaW5nID0gREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5NQVhfTEVOR1RIXG4pIHtcbiAgY29uc3Qga2V5ID0gVmFsaWRhdGlvbi5rZXkoVmFsaWRhdGlvbktleXMuTUFYX0xFTkdUSCk7XG4gIGNvbnN0IG1ldGE6IE1heExlbmd0aFZhbGlkYXRvck9wdGlvbnMgPSB7XG4gICAgW1ZhbGlkYXRpb25LZXlzLk1BWF9MRU5HVEhdOiB2YWx1ZSxcbiAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgIHR5cGVzOiBbU3RyaW5nLm5hbWUsIEFycmF5Lm5hbWUsIFNldC5uYW1lXSxcbiAgICBkZXNjcmlwdGlvbjogYGRlZmluZXMgdGhlIG1heCBsZW5ndGggb2YgdGhlIGF0dHJpYnV0ZSBhcyAke3ZhbHVlfSAoYXBwbGllcyB0byBzdHJpbmdzIG9yIGxpc3RzKWAsXG4gICAgYXN5bmM6IGZhbHNlLFxuICB9O1xuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUodmFsaWRhdGlvbk1ldGFkYXRhPE1heExlbmd0aFZhbGlkYXRvck9wdGlvbnM+KG1heGxlbmd0aCwga2V5LCBtZXRhKSlcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGEgUmVnRXhwIHBhdHRlcm4gdGhlIHByb3BlcnR5IG11c3QgcmVzcGVjdFxuICogQGRlc2NyaXB0aW9uIFZhbGlkYXRvcnMgdG8gdmFsaWRhdGUgYSBkZWNvcmF0ZWQgcHJvcGVydHkgbXVzdCB1c2Uga2V5IHtAbGluayBWYWxpZGF0aW9uS2V5cyNQQVRURVJOfVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZVxuICogQHBhcmFtIHtzdHJpbmd9IFttZXNzYWdlXSB0aGUgZXJyb3IgbWVzc2FnZS4gRGVmYXVsdHMgdG8ge0BsaW5rIERFRkFVTFRfRVJST1JfTUVTU0FHRVMjUEFUVEVSTn1cbiAqXG4gKiBAZnVuY3Rpb24gcGF0dGVyblxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhdHRlcm4oXG4gIHZhbHVlOiBSZWdFeHAgfCBzdHJpbmcsXG4gIG1lc3NhZ2U6IHN0cmluZyA9IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuUEFUVEVSTlxuKSB7XG4gIGNvbnN0IGtleSA9IFZhbGlkYXRpb24ua2V5KFZhbGlkYXRpb25LZXlzLlBBVFRFUk4pO1xuICBjb25zdCBtZXRhOiBQYXR0ZXJuVmFsaWRhdG9yT3B0aW9ucyA9IHtcbiAgICBbVmFsaWRhdGlvbktleXMuUEFUVEVSTl06XG4gICAgICB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgPyB2YWx1ZSA6IHZhbHVlLnRvU3RyaW5nKCksXG4gICAgbWVzc2FnZTogbWVzc2FnZSxcbiAgICB0eXBlczogW1N0cmluZy5uYW1lXSxcbiAgICBkZXNjcmlwdGlvbjogYGFzc2lnbnMgdGhlICR7dmFsdWUgPT09IFwic3RyaW5nXCIgPyB2YWx1ZSA6IHZhbHVlLnRvU3RyaW5nKCl9IHBhdHRlcm4gdG8gdGhlIGF0dHJpYnV0ZWAsXG4gICAgYXN5bmM6IGZhbHNlLFxuICB9O1xuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUodmFsaWRhdGlvbk1ldGFkYXRhPFBhdHRlcm5WYWxpZGF0b3JPcHRpb25zPihwYXR0ZXJuLCBrZXksIG1ldGEpKVxuICAgIC5hcHBseSgpO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IERlZmluZXMgdGhlIHByb3BlcnR5IGFzIGFuIGVtYWlsXG4gKiBAZGVzY3JpcHRpb24gVmFsaWRhdG9ycyB0byB2YWxpZGF0ZSBhIGRlY29yYXRlZCBwcm9wZXJ0eSBtdXN0IHVzZSBrZXkge0BsaW5rIFZhbGlkYXRpb25LZXlzI0VNQUlMfVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gdGhlIGVycm9yIG1lc3NhZ2UuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX0VSUk9SX01FU1NBR0VTI0VNQUlMfVxuICpcbiAqIEBmdW5jdGlvbiBlbWFpbFxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVtYWlsKG1lc3NhZ2U6IHN0cmluZyA9IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuRU1BSUwpIHtcbiAgY29uc3Qga2V5ID0gVmFsaWRhdGlvbi5rZXkoVmFsaWRhdGlvbktleXMuRU1BSUwpO1xuICBjb25zdCBtZXRhOiBQYXR0ZXJuVmFsaWRhdG9yT3B0aW9ucyA9IHtcbiAgICBbVmFsaWRhdGlvbktleXMuUEFUVEVSTl06IERFRkFVTFRfUEFUVEVSTlMuRU1BSUwudG9TdHJpbmcoKSxcbiAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgIHR5cGVzOiBbU3RyaW5nLm5hbWVdLFxuICAgIGRlc2NyaXB0aW9uOiBcIm1hcmtzIHR