@decaf-ts/decorator-validation
Version:
simple decorator based validation engine
117 lines • 15.6 kB
JavaScript
import { DEFAULT_ERROR_MESSAGES } from "./constants.js";
import { sf } from "./../../utils/strings.js";
import { Reflection } from "@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
*/
export class BaseValidator {
constructor(async, message = 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 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.checkTypes(value, this.acceptedTypes))
return this.getMessage(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"];
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzZVZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy92YWxpZGF0aW9uL1ZhbGlkYXRvcnMvQmFzZVZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsdUJBQW9CO0FBQ3JELE9BQU8sRUFBRSxFQUFFLEVBQUUsaUNBQTRCO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUtsRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4REc7QUFDSCxNQUFNLE9BQWdCLGFBQWE7SUFRakMsWUFDRSxLQUFZLEVBQ1osVUFBa0Isc0JBQXNCLENBQUMsT0FBTyxFQUNoRCxHQUFHLGFBQXVCO1FBRTFCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBRXZCLElBQUksYUFBYSxDQUFDLE1BQU07WUFBRSxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUM3RCxJQUFJLElBQUksQ0FBQyxhQUFhO1lBQ3BCLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUN6QyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQVEsQ0FDMUIsQ0FBQztJQUNiLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ08sVUFBVSxDQUFDLE9BQWUsRUFBRSxHQUFHLElBQVc7UUFDbEQsT0FBTyxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNLLHFCQUFxQixDQUMzQixPQUtnRDtRQUVoRCxPQUFPLFVBRUwsS0FBVSxFQUNWLE9BQVUsRUFDVixLQUFzQixFQUN0QixHQUFHLElBQVc7WUFFZCxJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYTtnQkFDNUMsT0FBTyxPQUFPLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUNqRCxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQztnQkFDbkQsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUNwQixzQkFBc0IsQ0FBQyxJQUFJLEVBQzNCLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUM3QixPQUFPLEtBQUssQ0FDYixDQUFDO1lBQ0osT0FBTyxPQUFPLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUNqRCxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2YsQ0FBQztJQXlCRDs7O09BR0c7SUFDSCxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQVE7UUFDekIsT0FBTyxHQUFHLENBQUMsV0FBVyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0MsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgc2YgfSBmcm9tIFwiLi4vLi4vdXRpbHMvc3RyaW5nc1wiO1xuaW1wb3J0IHsgUmVmbGVjdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuaW1wb3J0IHsgVmFsaWRhdG9yT3B0aW9ucyB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHR5cGUgeyBQYXRoUHJveHkgfSBmcm9tIFwiLi4vLi4vdXRpbHNcIjtcbmltcG9ydCB0eXBlIHsgQ29uZGl0aW9uYWxBc3luYyB9IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBYnN0cmFjdCBiYXNlIGNsYXNzIGZvciBhbGwgdmFsaWRhdG9ycyBpbiB0aGUgdmFsaWRhdGlvbiBmcmFtZXdvcmsuXG4gKiBAc3VtbWFyeSBUaGUgQmFzZVZhbGlkYXRvciBjbGFzcyBwcm92aWRlcyB0aGUgZm91bmRhdGlvbiBmb3IgYWxsIHN5bmNocm9ub3VzIGFuZCBhc3luY2hyb25vdXMgdmFsaWRhdG9yIGltcGxlbWVudGF0aW9ucy5cbiAqIEl0IGhhbmRsZXMgdHlwZSBjaGVja2luZywgZXJyb3IgbWVzc2FnZSBmb3JtYXR0aW5nLCBhbmQgZGVmaW5lcyB0aGUgaW50ZXJmYWNlIHRoYXQgYWxsIHZhbGlkYXRvcnMgbXVzdCBpbXBsZW1lbnQuXG4gKiBUaGlzIGNsYXNzIGlzIGRlc2lnbmVkIHRvIGJlIGV4dGVuZGVkIGJ5IHNwZWNpZmljIHZhbGlkYXRvciBjbGFzc2VzIHRoYXQgZGVmaW5lIHRoZWlyIG93biB2YWxpZGF0aW9uIGxvZ2ljLlxuICpcbiAqIEB0ZW1wbGF0ZSBWIC0gVmFsaWRhdG9yIG9wdGlvbnMgdHlwZVxuICogQHRlbXBsYXRlIElzQXN5bmMgLSBXaGV0aGVyIHRoZSB2YWxpZGF0b3IgaXMgYXN5bmMgKHRydWUpIG9yIHN5bmMgKGZhbHNlKS4gRGVmYXVsdCBgZmFsc2VgLlxuICpcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYXN5bmMgLSBEZWZpbmVzIGlmIHRoZSB2YWxpZGF0b3IgaXMgYXN5bmMgKG11c3QgbWF0Y2ggdGhlIHN1YmNsYXNzIHNpZ25hdHVyZSlcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gRGVmYXVsdCBlcnJvciBtZXNzYWdlIHRvIGRpc3BsYXkgd2hlbiB2YWxpZGF0aW9uIGZhaWxzIChkZWZhdWx0cyB0byB7QGxpbmsgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyNERUZBVUxUfSlcbiAqIEBwYXJhbSB7c3RyaW5nW119IGFjY2VwdGVkVHlwZXMgLSBUeXBlIG5hbWVzIHRoYXQgdGhpcyB2YWxpZGF0b3IgYWNjZXB0cyAodXNlZCBmb3IgcnVudGltZSB0eXBlIGNoZWNraW5nKVxuICpcbiAqIEBjbGFzcyBCYXNlVmFsaWRhdG9yXG4gKiBAYWJzdHJhY3RcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gRXhhbXBsZSBvZiBhIHN5bmNocm9ub3VzIHZhbGlkYXRvclxuICogY2xhc3MgU3luY1ZhbGlkYXRvciBleHRlbmRzIEJhc2VWYWxpZGF0b3I8U29tZU9wdGlvbnMsIGZhbHNlPiB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIHN1cGVyKGZhbHNlLCBcIlN5bmMgdmFsaWRhdGlvbiBmYWlsZWRcIiwgU3RyaW5nLm5hbWUpO1xuICogICB9XG4gKlxuICogICBwdWJsaWMgaGFzRXJyb3JzKHZhbHVlOiBhbnksIG9wdGlvbnM/OiBTb21lT3B0aW9ucyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gKiAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJzdHJpbmdcIikgcmV0dXJuIHRoaXMuZ2V0TWVzc2FnZSh0aGlzLm1lc3NhZ2UpO1xuICogICAgIHJldHVybiB1bmRlZmluZWQ7XG4gKiAgIH1cbiAqIH1cbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gRXhhbXBsZSBvZiBhbiBhc3luY2hyb25vdXMgY3VzdG9tIHZhbGlkYXRvclxuICogY2xhc3MgQXN5bmNWYWxpZGF0b3IgZXh0ZW5kcyBCYXNlVmFsaWRhdG9yPFNvbWVPcHRpb25zLCB0cnVlPiB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIHN1cGVyKHRydWUsIFwiQXN5bmMgdmFsaWRhdGlvbiBmYWlsZWRcIiwgU3RyaW5nLm5hbWUpO1xuICogICB9XG4gKlxuICogICBwdWJsaWMgYXN5bmMgaGFzRXJyb3JzKHZhbHVlOiBhbnksIG9wdGlvbnM/OiBTb21lT3B0aW9ucyk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gKiAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc29tZUFzeW5jQ2hlY2sodmFsdWUpO1xuICogICAgIGlmICghcmVzdWx0KSByZXR1cm4gdGhpcy5nZXRNZXNzYWdlKHRoaXMubWVzc2FnZSk7XG4gKiAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAqICAgfVxuICogfVxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQyBhcyBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgViBhcyBWYWxpZGF0b3IgU3ViY2xhc3NcbiAqICAgcGFydGljaXBhbnQgQiBhcyBCYXNlVmFsaWRhdG9yXG4gKlxuICogICBDLT4+VjogbmV3IEN1c3RvbVZhbGlkYXRvcihhc3luYywgbWVzc2FnZSlcbiAqICAgVi0+PkI6IHN1cGVyKGFzeW5jLCBtZXNzYWdlLCBhY2NlcHRlZFR5cGVzKVxuICogICBCLT4+QjogU3RvcmUgbWVzc2FnZSwgYXN5bmMgZmxhZywgYW5kIGFjY2VwdGVkIHR5cGVzXG4gKiAgIEItPj5COiBPcHRpb25hbGx5IHdyYXAgaGFzRXJyb3JzIHdpdGggdHlwZSBjaGVja2luZ1xuICogICBDLT4+VjogaGFzRXJyb3JzKHZhbHVlLCBvcHRpb25zKVxuICogICBhbHQgdmFsdWUgdHlwZSBub3QgaW4gYWNjZXB0ZWRUeXBlc1xuICogICAgIEItLT4+QzogVHlwZSBlcnJvciBtZXNzYWdlXG4gKiAgIGVsc2UgdmFsdWUgdHlwZSBpcyBhY2NlcHRlZFxuICogICAgIFYtPj5WOiBDdXN0b20gdmFsaWRhdGlvbiBsb2dpY1xuICogICAgIFYtLT4+QzogVmFsaWRhdGlvbiByZXN1bHRcbiAqICAgZW5kXG4gKlxuICogQGNhdGVnb3J5IFZhbGlkYXRvcnNcbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VWYWxpZGF0b3I8XG4gIFYgZXh0ZW5kcyBWYWxpZGF0b3JPcHRpb25zID0gVmFsaWRhdG9yT3B0aW9ucyxcbiAgQXN5bmMgZXh0ZW5kcyBib29sZWFuID0gZmFsc2UsXG4+IHtcbiAgcmVhZG9ubHkgbWVzc2FnZTogc3RyaW5nO1xuICByZWFkb25seSBhY2NlcHRlZFR5cGVzPzogc3RyaW5nW107XG4gIHJlYWRvbmx5IGFzeW5jPzogQXN5bmM7XG5cbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxuICAgIGFzeW5jOiBBc3luYyxcbiAgICBtZXNzYWdlOiBzdHJpbmcgPSBERUZBVUxUX0VSUk9SX01FU1NBR0VTLkRFRkFVTFQsXG4gICAgLi4uYWNjZXB0ZWRUeXBlczogc3RyaW5nW11cbiAgKSB7XG4gICAgdGhpcy5hc3luYyA9IGFzeW5jO1xuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XG5cbiAgICBpZiAoYWNjZXB0ZWRUeXBlcy5sZW5ndGgpIHRoaXMuYWNjZXB0ZWRUeXBlcyA9IGFjY2VwdGVkVHlwZXM7XG4gICAgaWYgKHRoaXMuYWNjZXB0ZWRUeXBlcylcbiAgICAgIHRoaXMuaGFzRXJyb3JzID0gdGhpcy5jaGVja1R5cGVBbmRIYXNFcnJvcnMoXG4gICAgICAgIHRoaXMuaGFzRXJyb3JzLmJpbmQodGhpcykgYXMgYW55XG4gICAgICApIGFzIGFueTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRm9ybWF0cyBhbiBlcnJvciBtZXNzYWdlIHdpdGggb3B0aW9uYWwgYXJndW1lbnRzXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBmb3JtYXR0ZWQgZXJyb3IgbWVzc2FnZSBieSByZXBsYWNpbmcgcGxhY2Vob2xkZXJzIHdpdGggcHJvdmlkZWQgYXJndW1lbnRzLlxuICAgKiBUaGlzIG1ldGhvZCB1c2VzIHRoZSBzdHJpbmcgZm9ybWF0dGluZyB1dGlsaXR5IHRvIGdlbmVyYXRlIGNvbnNpc3RlbnQgZXJyb3IgbWVzc2FnZXNcbiAgICogYWNyb3NzIGFsbCB2YWxpZGF0b3JzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBtZXNzYWdlIHRlbXBsYXRlIHdpdGggcGxhY2Vob2xkZXJzXG4gICAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gVmFsdWVzIHRvIGluc2VydCBpbnRvIHRoZSBtZXNzYWdlIHRlbXBsYXRlXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGZvcm1hdHRlZCBlcnJvciBtZXNzYWdlXG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIHByb3RlY3RlZCBnZXRNZXNzYWdlKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogYW55W10pIHtcbiAgICByZXR1cm4gc2YobWVzc2FnZSwgLi4uYXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSB0eXBlLWNoZWNraW5nIHdyYXBwZXIgYXJvdW5kIHRoZSBoYXNFcnJvcnMgbWV0aG9kXG4gICAqIEBzdW1tYXJ5IFdyYXBzIHRoZSBoYXNFcnJvcnMgbWV0aG9kIHdpdGggdHlwZSB2YWxpZGF0aW9uIGxvZ2ljIHRvIGVuc3VyZSB0aGF0XG4gICAqIHRoZSB2YWx1ZSBiZWluZyB2YWxpZGF0ZWQgaXMgb2YgYW4gYWNjZXB0ZWQgdHlwZSBiZWZvcmUgcGVyZm9ybWluZyBzcGVjaWZpYyB2YWxpZGF0aW9uLlxuICAgKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgZHVyaW5nIGNvbnN0cnVjdGlvbiBpZiBhY2NlcHRlZFR5cGVzIGFyZSBwcm92aWRlZC5cbiAgICpcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gdW5ib3VuZCAtIFRoZSBvcmlnaW5hbCBoYXNFcnJvcnMgbWV0aG9kIHRvIGJlIHdyYXBwZWRcbiAgICogQHJldHVybiB7RnVuY3Rpb259IEEgbmV3IGZ1bmN0aW9uIHRoYXQgcGVyZm9ybXMgdHlwZSBjaGVja2luZyBiZWZvcmUgY2FsbGluZyB0aGUgb3JpZ2luYWwgbWV0aG9kXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGNoZWNrVHlwZUFuZEhhc0Vycm9ycyhcbiAgICB1bmJvdW5kOiAoXG4gICAgICB2YWx1ZTogYW55LFxuICAgICAgb3B0aW9ucz86IFYsXG4gICAgICBwcm94eT86IFBhdGhQcm94eTxhbnk+LFxuICAgICAgLi4uYXJnczogYW55W11cbiAgICApID0+IENvbmRpdGlvbmFsQXN5bmM8QXN5bmMsIHN0cmluZyB8IHVuZGVmaW5lZD5cbiAgKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICAgIHRoaXM6IEJhc2VWYWxpZGF0b3IsXG4gICAgICB2YWx1ZTogYW55LFxuICAgICAgb3B0aW9uczogVixcbiAgICAgIHByb3h5PzogUGF0aFByb3h5PGFueT4sXG4gICAgICAuLi5hcmdzOiBhbnlbXVxuICAgICkge1xuICAgICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgIXRoaXMuYWNjZXB0ZWRUeXBlcylcbiAgICAgICAgcmV0dXJuIHVuYm91bmQodmFsdWUsIG9wdGlvbnMsIHByb3h5LCAuLi5hcmdzKTtcbiAgICAgIGlmICghUmVmbGVjdGlvbi5jaGVja1R5cGVzKHZhbHVlLCB0aGlzLmFjY2VwdGVkVHlwZXMpKVxuICAgICAgICByZXR1cm4gdGhpcy5nZXRNZXNzYWdlKFxuICAgICAgICAgIERFRkFVTFRfRVJST1JfTUVTU0FHRVMuVFlQRSxcbiAgICAgICAgICB0aGlzLmFjY2VwdGVkVHlwZXMuam9pbihcIiwgXCIpLFxuICAgICAgICAgIHR5cGVvZiB2YWx1ZVxuICAgICAgICApO1xuICAgICAgcmV0dXJuIHVuYm91bmQodmFsdWUsIG9wdGlvbnMsIHByb3h5LCAuLi5hcmdzKTtcbiAgICB9LmJpbmQodGhpcyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFZhbGlkYXRlcyBhIHZhbHVlIGFnYWluc3Qgc3BlY2lmaWMgdmFsaWRhdGlvbiBydWxlc1xuICAgKiBAc3VtbWFyeSBBYnN0cmFjdCBtZXRob2QgdGhhdCBtdXN0IGJlIGltcGxlbWVudGVkIGJ5IGFsbCB2YWxpZGF0b3Igc3ViY2xhc3Nlcy5cbiAgICogVGhpcyBtZXRob2QgY29udGFpbnMgdGhlIGNvcmUgdmFsaWRhdGlvbiBsb2dpYyB0aGF0IGRldGVybWluZXMgd2hldGhlciBhIHZhbHVlXG4gICAqIGlzIHZhbGlkIGFjY29yZGluZyB0byB0aGUgc3BlY2lmaWMgcnVsZXMgb2YgdGhlIHZhbGlkYXRvci4gSWYgdGhlIHZhbHVlIGlzIHZhbGlkLFxuICAgKiB0aGUgbWV0aG9kIHJldHVybnMgdW5kZWZpbmVkOyBvdGhlcndpc2UsIGl0IHJldHVybnMgYW4gZXJyb3IgbWVzc2FnZS5cbiAgICpcbiAgICogQHRlbXBsYXRlIFYgLSBUeXBlIG9mIHRoZSBvcHRpb25zIG9iamVjdCB0aGF0IGNhbiBiZSBwYXNzZWQgdG8gdGhlIHZhbGlkYXRvclxuICAgKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gdmFsaWRhdGVcbiAgICogQHBhcmFtIHtWfSBbb3B0aW9uc10gLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIGN1c3RvbWl6aW5nIHZhbGlkYXRpb24gYmVoYXZpb3JcbiAgICogQHBhcmFtIHtQYXRoUHJveHk8YW55Pn0gcHJveHkgLVxuICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IEVycm9yIG1lc3NhZ2UgaWYgdmFsaWRhdGlvbiBmYWlscywgdW5kZWZpbmVkIGlmIHZhbGlkYXRpb24gcGFzc2VzXG4gICAqXG4gICAqIEBhYnN0cmFjdFxuICAgKlxuICAgKiBAc2VlIE1vZGVsI3ZhbGlkYXRlXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgaGFzRXJyb3JzKFxuICAgIHZhbHVlOiBhbnksXG4gICAgb3B0aW9ucz86IFYsXG4gICAgcHJveHk/OiBQYXRoUHJveHk8YW55PlxuICApOiBDb25kaXRpb25hbEFzeW5jPEFzeW5jLCBzdHJpbmcgfCB1bmRlZmluZWQ+O1xuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBEdWNrIHR5cGluZyBmb3IgVmFsaWRhdG9yc1xuICAgKiBAcGFyYW0gdmFsXG4gICAqL1xuICBzdGF0aWMgaXNWYWxpZGF0b3IodmFsOiBhbnkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdmFsLmNvbnN0cnVjdG9yICYmICEhdmFsW1wiaGFzRXJyb3JzXCJdO1xuICB9XG59XG4iXX0=