UNPKG

@decaf-ts/decorator-validation

Version:
121 lines 15.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseValidator = void 0; const constants_1 = require("./constants.cjs"); const strings_1 = require("./../../utils/strings.cjs"); const reflection_1 = require("@decaf-ts/reflection"); /** * @description Abstract base class for all validators in the validation framework. * @summary The BaseValidator class provides the foundation for all synchronous and asynchronous validator implementations. * It handles type checking, error message formatting, and defines the interface that all validators must implement. * This class is designed to be extended by specific validator classes that define their own validation logic. * * @template V - Validator options type * @template IsAsync - Whether the validator is async (true) or sync (false). Default `false`. * * @param {boolean} async - Defines if the validator is async (must match the subclass signature) * @param {string} message - Default error message to display when validation fails (defaults to {@link DEFAULT_ERROR_MESSAGES#DEFAULT}) * @param {string[]} acceptedTypes - Type names that this validator accepts (used for runtime type checking) * * @class BaseValidator * @abstract * * @example * // Example of a synchronous validator * class SyncValidator extends BaseValidator<SomeOptions, false> { * constructor() { * super(false, "Sync validation failed", String.name); * } * * public hasErrors(value: any, options?: SomeOptions): string | undefined { * if (typeof value !== "string") return this.getMessage(this.message); * return undefined; * } * } * * @example * // Example of an asynchronous custom validator * class AsyncValidator extends BaseValidator<SomeOptions, true> { * constructor() { * super(true, "Async validation failed", String.name); * } * * public async hasErrors(value: any, options?: SomeOptions): Promise<string | undefined> { * const result = await someAsyncCheck(value); * if (!result) return this.getMessage(this.message); * return undefined; * } * } * * @mermaid * sequenceDiagram * participant C as Client * participant V as Validator Subclass * participant B as BaseValidator * * C->>V: new CustomValidator(async, message) * V->>B: super(async, message, acceptedTypes) * B->>B: Store message, async flag, and accepted types * B->>B: Optionally wrap hasErrors with type checking * C->>V: hasErrors(value, options) * alt value type not in acceptedTypes * B-->>C: Type error message * else value type is accepted * V->>V: Custom validation logic * V-->>C: Validation result * end * * @category Validators */ class BaseValidator { constructor(async, message = constants_1.DEFAULT_ERROR_MESSAGES.DEFAULT, ...acceptedTypes) { this.async = async; this.message = message; if (acceptedTypes.length) this.acceptedTypes = acceptedTypes; if (this.acceptedTypes) this.hasErrors = this.checkTypeAndHasErrors(this.hasErrors.bind(this)); } /** * @description Formats an error message with optional arguments * @summary Creates a formatted error message by replacing placeholders with provided arguments. * This method uses the string formatting utility to generate consistent error messages * across all validators. * * @param {string} message - The message template with placeholders * @param {...any} args - Values to insert into the message template * @return {string} The formatted error message * @protected */ getMessage(message, ...args) { return (0, strings_1.sf)(message, ...args); } /** * @description Creates a type-checking wrapper around the hasErrors method * @summary Wraps the hasErrors method with type validation logic to ensure that * the value being validated is of an accepted type before performing specific validation. * This method is called during construction if acceptedTypes are provided. * * @param {Function} unbound - The original hasErrors method to be wrapped * @return {Function} A new function that performs type checking before calling the original method * @private */ checkTypeAndHasErrors(unbound) { return function (value, options, proxy, ...args) { if (value === undefined || !this.acceptedTypes) return unbound(value, options, proxy, ...args); if (!reflection_1.Reflection.checkTypes(value, this.acceptedTypes)) return this.getMessage(constants_1.DEFAULT_ERROR_MESSAGES.TYPE, this.acceptedTypes.join(", "), typeof value); return unbound(value, options, proxy, ...args); }.bind(this); } /** * @summary Duck typing for Validators * @param val */ static isValidator(val) { return val.constructor && !!val["hasErrors"]; } } exports.BaseValidator = BaseValidator; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzZVZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy92YWxpZGF0aW9uL1ZhbGlkYXRvcnMvQmFzZVZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQ0FBcUQ7QUFDckQsdURBQXlDO0FBQ3pDLHFEQUFrRDtBQUtsRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4REc7QUFDSCxNQUFzQixhQUFhO0lBUWpDLFlBQ0UsS0FBWSxFQUNaLFVBQWtCLGtDQUFzQixDQUFDLE9BQU8sRUFDaEQsR0FBRyxhQUF1QjtRQUUxQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUV2QixJQUFJLGFBQWEsQ0FBQyxNQUFNO1lBQUUsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDN0QsSUFBSSxJQUFJLENBQUMsYUFBYTtZQUNwQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FDekMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFRLENBQzFCLENBQUM7SUFDYixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNPLFVBQVUsQ0FBQyxPQUFlLEVBQUUsR0FBRyxJQUFXO1FBQ2xELE9BQU8sSUFBQSxZQUFFLEVBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNLLHFCQUFxQixDQUMzQixPQUtnRDtRQUVoRCxPQUFPLFVBRUwsS0FBVSxFQUNWLE9BQVUsRUFDVixLQUFzQixFQUN0QixHQUFHLElBQVc7WUFFZCxJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYTtnQkFDNUMsT0FBTyxPQUFPLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUNqRCxJQUFJLENBQUMsdUJBQVUsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUM7Z0JBQ25ELE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FDcEIsa0NBQXNCLENBQUMsSUFBSSxFQUMzQixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFDN0IsT0FBTyxLQUFLLENBQ2IsQ0FBQztZQUNKLE9BQU8sT0FBTyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNmLENBQUM7SUF5QkQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLFdBQVcsQ0FBQyxHQUFRO1FBQ3pCLE9BQU8sR0FBRyxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLENBQUM7Q0FDRjtBQXpHRCxzQ0F5R0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBERUZBVUxUX0VSUk9SX01FU1NBR0VTIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBzZiB9IGZyb20gXCIuLi8uLi91dGlscy9zdHJpbmdzXCI7XG5pbXBvcnQgeyBSZWZsZWN0aW9uIH0gZnJvbSBcIkBkZWNhZi10cy9yZWZsZWN0aW9uXCI7XG5pbXBvcnQgeyBWYWxpZGF0b3JPcHRpb25zIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgdHlwZSB7IFBhdGhQcm94eSB9IGZyb20gXCIuLi8uLi91dGlsc1wiO1xuaW1wb3J0IHR5cGUgeyBDb25kaXRpb25hbEFzeW5jIH0gZnJvbSBcIi4uLy4uL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEFic3RyYWN0IGJhc2UgY2xhc3MgZm9yIGFsbCB2YWxpZGF0b3JzIGluIHRoZSB2YWxpZGF0aW9uIGZyYW1ld29yay5cbiAqIEBzdW1tYXJ5IFRoZSBCYXNlVmFsaWRhdG9yIGNsYXNzIHByb3ZpZGVzIHRoZSBmb3VuZGF0aW9uIGZvciBhbGwgc3luY2hyb25vdXMgYW5kIGFzeW5jaHJvbm91cyB2YWxpZGF0b3IgaW1wbGVtZW50YXRpb25zLlxuICogSXQgaGFuZGxlcyB0eXBlIGNoZWNraW5nLCBlcnJvciBtZXNzYWdlIGZvcm1hdHRpbmcsIGFuZCBkZWZpbmVzIHRoZSBpbnRlcmZhY2UgdGhhdCBhbGwgdmFsaWRhdG9ycyBtdXN0IGltcGxlbWVudC5cbiAqIFRoaXMgY2xhc3MgaXMgZGVzaWduZWQgdG8gYmUgZXh0ZW5kZWQgYnkgc3BlY2lmaWMgdmFsaWRhdG9yIGNsYXNzZXMgdGhhdCBkZWZpbmUgdGhlaXIgb3duIHZhbGlkYXRpb24gbG9naWMuXG4gKlxuICogQHRlbXBsYXRlIFYgLSBWYWxpZGF0b3Igb3B0aW9ucyB0eXBlXG4gKiBAdGVtcGxhdGUgSXNBc3luYyAtIFdoZXRoZXIgdGhlIHZhbGlkYXRvciBpcyBhc3luYyAodHJ1ZSkgb3Igc3luYyAoZmFsc2UpLiBEZWZhdWx0IGBmYWxzZWAuXG4gKlxuICogQHBhcmFtIHtib29sZWFufSBhc3luYyAtIERlZmluZXMgaWYgdGhlIHZhbGlkYXRvciBpcyBhc3luYyAobXVzdCBtYXRjaCB0aGUgc3ViY2xhc3Mgc2lnbmF0dXJlKVxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBEZWZhdWx0IGVycm9yIG1lc3NhZ2UgdG8gZGlzcGxheSB3aGVuIHZhbGlkYXRpb24gZmFpbHMgKGRlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX0VSUk9SX01FU1NBR0VTI0RFRkFVTFR9KVxuICogQHBhcmFtIHtzdHJpbmdbXX0gYWNjZXB0ZWRUeXBlcyAtIFR5cGUgbmFtZXMgdGhhdCB0aGlzIHZhbGlkYXRvciBhY2NlcHRzICh1c2VkIGZvciBydW50aW1lIHR5cGUgY2hlY2tpbmcpXG4gKlxuICogQGNsYXNzIEJhc2VWYWxpZGF0b3JcbiAqIEBhYnN0cmFjdFxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBFeGFtcGxlIG9mIGEgc3luY2hyb25vdXMgdmFsaWRhdG9yXG4gKiBjbGFzcyBTeW5jVmFsaWRhdG9yIGV4dGVuZHMgQmFzZVZhbGlkYXRvcjxTb21lT3B0aW9ucywgZmFsc2U+IHtcbiAqICAgY29uc3RydWN0b3IoKSB7XG4gKiAgICAgc3VwZXIoZmFsc2UsIFwiU3luYyB2YWxpZGF0aW9uIGZhaWxlZFwiLCBTdHJpbmcubmFtZSk7XG4gKiAgIH1cbiAqXG4gKiAgIHB1YmxpYyBoYXNFcnJvcnModmFsdWU6IGFueSwgb3B0aW9ucz86IFNvbWVPcHRpb25zKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAqICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSBcInN0cmluZ1wiKSByZXR1cm4gdGhpcy5nZXRNZXNzYWdlKHRoaXMubWVzc2FnZSk7XG4gKiAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAqICAgfVxuICogfVxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBFeGFtcGxlIG9mIGFuIGFzeW5jaHJvbm91cyBjdXN0b20gdmFsaWRhdG9yXG4gKiBjbGFzcyBBc3luY1ZhbGlkYXRvciBleHRlbmRzIEJhc2VWYWxpZGF0b3I8U29tZU9wdGlvbnMsIHRydWU+IHtcbiAqICAgY29uc3RydWN0b3IoKSB7XG4gKiAgICAgc3VwZXIodHJ1ZSwgXCJBc3luYyB2YWxpZGF0aW9uIGZhaWxlZFwiLCBTdHJpbmcubmFtZSk7XG4gKiAgIH1cbiAqXG4gKiAgIHB1YmxpYyBhc3luYyBoYXNFcnJvcnModmFsdWU6IGFueSwgb3B0aW9ucz86IFNvbWVPcHRpb25zKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAqICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzb21lQXN5bmNDaGVjayh2YWx1ZSk7XG4gKiAgICAgaWYgKCFyZXN1bHQpIHJldHVybiB0aGlzLmdldE1lc3NhZ2UodGhpcy5tZXNzYWdlKTtcbiAqICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICogICB9XG4gKiB9XG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDIGFzIENsaWVudFxuICogICBwYXJ0aWNpcGFudCBWIGFzIFZhbGlkYXRvciBTdWJjbGFzc1xuICogICBwYXJ0aWNpcGFudCBCIGFzIEJhc2VWYWxpZGF0b3JcbiAqXG4gKiAgIEMtPj5WOiBuZXcgQ3VzdG9tVmFsaWRhdG9yKGFzeW5jLCBtZXNzYWdlKVxuICogICBWLT4+Qjogc3VwZXIoYXN5bmMsIG1lc3NhZ2UsIGFjY2VwdGVkVHlwZXMpXG4gKiAgIEItPj5COiBTdG9yZSBtZXNzYWdlLCBhc3luYyBmbGFnLCBhbmQgYWNjZXB0ZWQgdHlwZXNcbiAqICAgQi0+PkI6IE9wdGlvbmFsbHkgd3JhcCBoYXNFcnJvcnMgd2l0aCB0eXBlIGNoZWNraW5nXG4gKiAgIEMtPj5WOiBoYXNFcnJvcnModmFsdWUsIG9wdGlvbnMpXG4gKiAgIGFsdCB2YWx1ZSB0eXBlIG5vdCBpbiBhY2NlcHRlZFR5cGVzXG4gKiAgICAgQi0tPj5DOiBUeXBlIGVycm9yIG1lc3NhZ2VcbiAqICAgZWxzZSB2YWx1ZSB0eXBlIGlzIGFjY2VwdGVkXG4gKiAgICAgVi0+PlY6IEN1c3RvbSB2YWxpZGF0aW9uIGxvZ2ljXG4gKiAgICAgVi0tPj5DOiBWYWxpZGF0aW9uIHJlc3VsdFxuICogICBlbmRcbiAqXG4gKiBAY2F0ZWdvcnkgVmFsaWRhdG9yc1xuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQmFzZVZhbGlkYXRvcjxcbiAgViBleHRlbmRzIFZhbGlkYXRvck9wdGlvbnMgPSBWYWxpZGF0b3JPcHRpb25zLFxuICBBc3luYyBleHRlbmRzIGJvb2xlYW4gPSBmYWxzZSxcbj4ge1xuICByZWFkb25seSBtZXNzYWdlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGFjY2VwdGVkVHlwZXM/OiBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgYXN5bmM/OiBBc3luYztcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoXG4gICAgYXN5bmM6IEFzeW5jLFxuICAgIG1lc3NhZ2U6IHN0cmluZyA9IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuREVGQVVMVCxcbiAgICAuLi5hY2NlcHRlZFR5cGVzOiBzdHJpbmdbXVxuICApIHtcbiAgICB0aGlzLmFzeW5jID0gYXN5bmM7XG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcblxuICAgIGlmIChhY2NlcHRlZFR5cGVzLmxlbmd0aCkgdGhpcy5hY2NlcHRlZFR5cGVzID0gYWNjZXB0ZWRUeXBlcztcbiAgICBpZiAodGhpcy5hY2NlcHRlZFR5cGVzKVxuICAgICAgdGhpcy5oYXNFcnJvcnMgPSB0aGlzLmNoZWNrVHlwZUFuZEhhc0Vycm9ycyhcbiAgICAgICAgdGhpcy5oYXNFcnJvcnMuYmluZCh0aGlzKSBhcyBhbnlcbiAgICAgICkgYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBGb3JtYXRzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBvcHRpb25hbCBhcmd1bWVudHNcbiAgICogQHN1bW1hcnkgQ3JlYXRlcyBhIGZvcm1hdHRlZCBlcnJvciBtZXNzYWdlIGJ5IHJlcGxhY2luZyBwbGFjZWhvbGRlcnMgd2l0aCBwcm92aWRlZCBhcmd1bWVudHMuXG4gICAqIFRoaXMgbWV0aG9kIHVzZXMgdGhlIHN0cmluZyBmb3JtYXR0aW5nIHV0aWxpdHkgdG8gZ2VuZXJhdGUgY29uc2lzdGVudCBlcnJvciBtZXNzYWdlc1xuICAgKiBhY3Jvc3MgYWxsIHZhbGlkYXRvcnMuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIG1lc3NhZ2UgdGVtcGxhdGUgd2l0aCBwbGFjZWhvbGRlcnNcbiAgICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBWYWx1ZXMgdG8gaW5zZXJ0IGludG8gdGhlIG1lc3NhZ2UgdGVtcGxhdGVcbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgZm9ybWF0dGVkIGVycm9yIG1lc3NhZ2VcbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgcHJvdGVjdGVkIGdldE1lc3NhZ2UobWVzc2FnZTogc3RyaW5nLCAuLi5hcmdzOiBhbnlbXSkge1xuICAgIHJldHVybiBzZihtZXNzYWdlLCAuLi5hcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIHR5cGUtY2hlY2tpbmcgd3JhcHBlciBhcm91bmQgdGhlIGhhc0Vycm9ycyBtZXRob2RcbiAgICogQHN1bW1hcnkgV3JhcHMgdGhlIGhhc0Vycm9ycyBtZXRob2Qgd2l0aCB0eXBlIHZhbGlkYXRpb24gbG9naWMgdG8gZW5zdXJlIHRoYXRcbiAgICogdGhlIHZhbHVlIGJlaW5nIHZhbGlkYXRlZCBpcyBvZiBhbiBhY2NlcHRlZCB0eXBlIGJlZm9yZSBwZXJmb3JtaW5nIHNwZWNpZmljIHZhbGlkYXRpb24uXG4gICAqIFRoaXMgbWV0aG9kIGlzIGNhbGxlZCBkdXJpbmcgY29uc3RydWN0aW9uIGlmIGFjY2VwdGVkVHlwZXMgYXJlIHByb3ZpZGVkLlxuICAgKlxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSB1bmJvdW5kIC0gVGhlIG9yaWdpbmFsIGhhc0Vycm9ycyBtZXRob2QgdG8gYmUgd3JhcHBlZFxuICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gQSBuZXcgZnVuY3Rpb24gdGhhdCBwZXJmb3JtcyB0eXBlIGNoZWNraW5nIGJlZm9yZSBjYWxsaW5nIHRoZSBvcmlnaW5hbCBtZXRob2RcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgY2hlY2tUeXBlQW5kSGFzRXJyb3JzKFxuICAgIHVuYm91bmQ6IChcbiAgICAgIHZhbHVlOiBhbnksXG4gICAgICBvcHRpb25zPzogVixcbiAgICAgIHByb3h5PzogUGF0aFByb3h5PGFueT4sXG4gICAgICAuLi5hcmdzOiBhbnlbXVxuICAgICkgPT4gQ29uZGl0aW9uYWxBc3luYzxBc3luYywgc3RyaW5nIHwgdW5kZWZpbmVkPlxuICApIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKFxuICAgICAgdGhpczogQmFzZVZhbGlkYXRvcixcbiAgICAgIHZhbHVlOiBhbnksXG4gICAgICBvcHRpb25zOiBWLFxuICAgICAgcHJveHk/OiBQYXRoUHJveHk8YW55PixcbiAgICAgIC4uLmFyZ3M6IGFueVtdXG4gICAgKSB7XG4gICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCAhdGhpcy5hY2NlcHRlZFR5cGVzKVxuICAgICAgICByZXR1cm4gdW5ib3VuZCh2YWx1ZSwgb3B0aW9ucywgcHJveHksIC4uLmFyZ3MpO1xuICAgICAgaWYgKCFSZWZsZWN0aW9uLmNoZWNrVHlwZXModmFsdWUsIHRoaXMuYWNjZXB0ZWRUeXBlcykpXG4gICAgICAgIHJldHVybiB0aGlzLmdldE1lc3NhZ2UoXG4gICAgICAgICAgREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5UWVBFLFxuICAgICAgICAgIHRoaXMuYWNjZXB0ZWRUeXBlcy5qb2luKFwiLCBcIiksXG4gICAgICAgICAgdHlwZW9mIHZhbHVlXG4gICAgICAgICk7XG4gICAgICByZXR1cm4gdW5ib3VuZCh2YWx1ZSwgb3B0aW9ucywgcHJveHksIC4uLmFyZ3MpO1xuICAgIH0uYmluZCh0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVmFsaWRhdGVzIGEgdmFsdWUgYWdhaW5zdCBzcGVjaWZpYyB2YWxpZGF0aW9uIHJ1bGVzXG4gICAqIEBzdW1tYXJ5IEFic3RyYWN0IG1ldGhvZCB0aGF0IG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgYWxsIHZhbGlkYXRvciBzdWJjbGFzc2VzLlxuICAgKiBUaGlzIG1ldGhvZCBjb250YWlucyB0aGUgY29yZSB2YWxpZGF0aW9uIGxvZ2ljIHRoYXQgZGV0ZXJtaW5lcyB3aGV0aGVyIGEgdmFsdWVcbiAgICogaXMgdmFsaWQgYWNjb3JkaW5nIHRvIHRoZSBzcGVjaWZpYyBydWxlcyBvZiB0aGUgdmFsaWRhdG9yLiBJZiB0aGUgdmFsdWUgaXMgdmFsaWQsXG4gICAqIHRoZSBtZXRob2QgcmV0dXJucyB1bmRlZmluZWQ7IG90aGVyd2lzZSwgaXQgcmV0dXJucyBhbiBlcnJvciBtZXNzYWdlLlxuICAgKlxuICAgKiBAdGVtcGxhdGUgViAtIFR5cGUgb2YgdGhlIG9wdGlvbnMgb2JqZWN0IHRoYXQgY2FuIGJlIHBhc3NlZCB0byB0aGUgdmFsaWRhdG9yXG4gICAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0ge1Z9IFtvcHRpb25zXSAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgY3VzdG9taXppbmcgdmFsaWRhdGlvbiBiZWhhdmlvclxuICAgKiBAcGFyYW0ge1BhdGhQcm94eTxhbnk+fSBwcm94eSAtXG4gICAqIEByZXR1cm4ge3N0cmluZyB8IHVuZGVmaW5lZH0gRXJyb3IgbWVzc2FnZSBpZiB2YWxpZGF0aW9uIGZhaWxzLCB1bmRlZmluZWQgaWYgdmFsaWRhdGlvbiBwYXNzZXNcbiAgICpcbiAgICogQGFic3RyYWN0XG4gICAqXG4gICAqIEBzZWUgTW9kZWwjdmFsaWRhdGVcbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCBoYXNFcnJvcnMoXG4gICAgdmFsdWU6IGFueSxcbiAgICBvcHRpb25zPzogVixcbiAgICBwcm94eT86IFBhdGhQcm94eTxhbnk+XG4gICk6IENvbmRpdGlvbmFsQXN5bmM8QXN5bmMsIHN0cmluZyB8IHVuZGVmaW5lZD47XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IER1Y2sgdHlwaW5nIGZvciBWYWxpZGF0b3JzXG4gICAqIEBwYXJhbSB2YWxcbiAgICovXG4gIHN0YXRpYyBpc1ZhbGlkYXRvcih2YWw6IGFueSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB2YWwuY29uc3RydWN0b3IgJiYgISF2YWxbXCJoYXNFcnJvcnNcIl07XG4gIH1cbn1cbiJdfQ==